diff --git a/devenv/dev-dashboards/datasource-testdata/new_features_in_v62.json b/devenv/dev-dashboards/datasource-testdata/new_features_in_v62.json
new file mode 100644
index 0000000000000..f3844bea1f399
--- /dev/null
+++ b/devenv/dev-dashboards/datasource-testdata/new_features_in_v62.json
@@ -0,0 +1,1337 @@
+{
+ "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": [
+ {
+ "content": "# v6.2 Feature Demos \n\nScroll down to view all demo panels. \n",
+ "gridPos": {
+ "h": 3,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 13,
+ "links": [],
+ "mode": "markdown",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 3
+ },
+ "id": 15,
+ "title": "Bar Gauge",
+ "type": "row"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 7,
+ "w": 24,
+ "x": 0,
+ "y": 4
+ },
+ "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": "Retro LED mode",
+ "type": "bargauge"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 10,
+ "w": 18,
+ "x": 0,
+ "y": 11
+ },
+ "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"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Gradient mode",
+ "type": "bargauge"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 10,
+ "w": 6,
+ "x": 18,
+ "y": 11
+ },
+ "id": 8,
+ "links": [],
+ "options": {
+ "displayMode": "basic",
+ "fieldOptions": {
+ "calcs": ["mean"],
+ "defaults": {
+ "decimals": null,
+ "max": 100,
+ "min": 0,
+ "unit": "watt"
+ },
+ "mappings": [],
+ "override": {},
+ "thresholds": [
+ {
+ "color": "blue",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "green",
+ "index": 1,
+ "value": 42.5
+ },
+ {
+ "color": "orange",
+ "index": 2,
+ "value": 80
+ },
+ {
+ "color": "red",
+ "index": 3,
+ "value": 90
+ }
+ ],
+ "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": "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",
+ "type": "bargauge"
+ },
+ {
+ "collapsed": false,
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 21
+ },
+ "id": 36,
+ "panels": [],
+ "title": "Gauge multi series",
+ "type": "row"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 6,
+ "w": 18,
+ "x": 0,
+ "y": 22
+ },
+ "id": 38,
+ "links": [],
+ "options": {
+ "fieldOptions": {
+ "calcs": ["mean"],
+ "defaults": {
+ "max": 100,
+ "min": 0,
+ "unit": "decgbytes"
+ },
+ "mappings": [],
+ "override": {},
+ "thresholds": [
+ {
+ "color": "green",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "red",
+ "index": 1,
+ "value": 80
+ }
+ ],
+ "values": false
+ },
+ "orientation": "auto",
+ "showThresholdLabels": false,
+ "showThresholdMarkers": true
+ },
+ "pluginVersion": "6.3.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": "random_walk"
+ },
+ {
+ "alias": "sda6",
+ "refId": "F",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "type": "gauge"
+ },
+ {
+ "content": " \n* The new Gauge and Bar Gauge repeat for every series, row or column your queries return.\n* Works great with table & time series data \n",
+ "gridPos": {
+ "h": 6,
+ "w": 6,
+ "x": 18,
+ "y": 22
+ },
+ "id": 40,
+ "links": [],
+ "mode": "markdown",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "Multiple Series or Rows",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 28
+ },
+ "id": 19,
+ "panels": [],
+ "title": "Panels With No Title",
+ "type": "row"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": true,
+ "colors": ["#299c46", "#73BF69", "#d44a3a"],
+ "datasource": "gdev-testdata",
+ "decimals": null,
+ "format": "ms",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 6,
+ "x": 0,
+ "y": 29
+ },
+ "id": 20,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "pluginVersion": "6.2.0-pre",
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "p99",
+ "prefixFontSize": "50%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "refId": "Q",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "type": "singlestat",
+ "valueFontSize": "120%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": true,
+ "colors": ["#299c46", "#73BF69", "#d44a3a"],
+ "datasource": "gdev-testdata",
+ "decimals": null,
+ "format": "ms",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 6,
+ "x": 6,
+ "y": 29
+ },
+ "id": 23,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "pluginVersion": "6.2.0-pre",
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "p95",
+ "prefixFontSize": "80%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "refId": "Q",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "type": "singlestat",
+ "valueFontSize": "120%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "cacheTimeout": null,
+ "colorBackground": false,
+ "colorValue": true,
+ "colors": ["#299c46", "#73BF69", "#d44a3a"],
+ "datasource": "gdev-testdata",
+ "decimals": null,
+ "format": "ms",
+ "gauge": {
+ "maxValue": 100,
+ "minValue": 0,
+ "show": false,
+ "thresholdLabels": false,
+ "thresholdMarkers": true
+ },
+ "gridPos": {
+ "h": 4,
+ "w": 6,
+ "x": 12,
+ "y": 29
+ },
+ "id": 24,
+ "interval": null,
+ "links": [],
+ "mappingType": 1,
+ "mappingTypes": [
+ {
+ "name": "value to text",
+ "value": 1
+ },
+ {
+ "name": "range to text",
+ "value": 2
+ }
+ ],
+ "maxDataPoints": 100,
+ "nullPointMode": "connected",
+ "nullText": null,
+ "pluginVersion": "6.2.0-pre",
+ "postfix": "",
+ "postfixFontSize": "50%",
+ "prefix": "p90",
+ "prefixFontSize": "80%",
+ "rangeMaps": [
+ {
+ "from": "null",
+ "text": "N/A",
+ "to": "null"
+ }
+ ],
+ "sparkline": {
+ "fillColor": "rgba(31, 118, 189, 0.18)",
+ "full": false,
+ "lineColor": "rgb(31, 120, 193)",
+ "show": true
+ },
+ "tableColumn": "",
+ "targets": [
+ {
+ "refId": "Q",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "thresholds": "",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "type": "singlestat",
+ "valueFontSize": "120%",
+ "valueMaps": [
+ {
+ "op": "=",
+ "text": "N/A",
+ "value": "null"
+ }
+ ],
+ "valueName": "avg"
+ },
+ {
+ "content": "In v6.2 if you remove the panel title the visualization will take up all the space available. \nThe panel header menu will be overlayed on top if you hover over the panel so you can still move & edit the panel. ",
+ "gridPos": {
+ "h": 4,
+ "w": 6,
+ "x": 18,
+ "y": 29
+ },
+ "id": 42,
+ "links": [],
+ "mode": "markdown",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "datasource": "gdev-testdata",
+ "gridPos": {
+ "h": 4,
+ "w": 24,
+ "x": 0,
+ "y": 33
+ },
+ "id": 17,
+ "links": [],
+ "options": {
+ "displayMode": "lcd",
+ "fieldOptions": {
+ "calcs": ["mean"],
+ "defaults": {
+ "max": 100,
+ "min": 0,
+ "title": "Completion rate",
+ "unit": "percent"
+ },
+ "mappings": [],
+ "override": {},
+ "thresholds": [
+ {
+ "color": "red",
+ "index": 0,
+ "value": null
+ },
+ {
+ "color": "red",
+ "index": 1,
+ "value": 80
+ }
+ ],
+ "values": false
+ },
+ "orientation": "horizontal"
+ },
+ "pluginVersion": "6.2.0-pre",
+ "targets": [
+ {
+ "refId": "Q",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "type": "bargauge"
+ },
+ {
+ "aliasColors": {
+ "A-series": "blue",
+ "B-series": "dark-purple",
+ "C-series": "purple",
+ "Q-series": "dark-blue"
+ },
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 3,
+ "gridPos": {
+ "h": 6,
+ "w": 24,
+ "x": 0,
+ "y": 37
+ },
+ "id": 26,
+ "legend": {
+ "alignAsTable": true,
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "rightSide": true,
+ "show": true,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pluginVersion": "6.2.0-pre",
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "Q",
+ "scenarioId": "random_walk"
+ },
+ {
+ "refId": "A",
+ "scenarioId": "random_walk"
+ },
+ {
+ "refId": "B",
+ "scenarioId": "random_walk"
+ },
+ {
+ "refId": "C",
+ "scenarioId": "random_walk"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 43
+ },
+ "id": 22,
+ "panels": [],
+ "title": "Lazy loading of panels",
+ "type": "row"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 15,
+ "x": 0,
+ "y": 44
+ },
+ "id": 28,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "A",
+ "scenarioId": "slow_query",
+ "stringInput": "5s"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Slow Query (5s)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "content": "\n# Lazy Loading\n\nAs you scroll down you will see that Grafana only loads & issues queries for these panels as they are scrolled in to view. \nThis greatly reduces the load on your data source backends if you have many long dashboards with many panels. \n\n\n",
+ "gridPos": {
+ "h": 40,
+ "w": 9,
+ "x": 15,
+ "y": 44
+ },
+ "id": 34,
+ "links": [],
+ "mode": "markdown",
+ "timeFrom": null,
+ "timeShift": null,
+ "title": "",
+ "transparent": true,
+ "type": "text"
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 15,
+ "x": 0,
+ "y": 52
+ },
+ "id": 30,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "A",
+ "scenarioId": "slow_query",
+ "stringInput": "5s"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Slow Query (5s)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 15,
+ "x": 0,
+ "y": 60
+ },
+ "id": 31,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "A",
+ "scenarioId": "slow_query",
+ "stringInput": "5s"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Slow Query (5s)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 15,
+ "x": 0,
+ "y": 68
+ },
+ "id": 32,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "A",
+ "scenarioId": "slow_query",
+ "stringInput": "5s"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Slow Query (5s)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "gdev-testdata",
+ "fill": 1,
+ "gridPos": {
+ "h": 8,
+ "w": 15,
+ "x": 0,
+ "y": 76
+ },
+ "id": 29,
+ "legend": {
+ "avg": false,
+ "current": false,
+ "max": false,
+ "min": false,
+ "show": false,
+ "total": false,
+ "values": false
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null",
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "spaceLength": 10,
+ "stack": false,
+ "steppedLine": false,
+ "targets": [
+ {
+ "refId": "A",
+ "scenarioId": "slow_query",
+ "stringInput": "5s"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Slow Query (5s)",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ }
+ ],
+ "refresh": "",
+ "schemaVersion": 18,
+ "style": "dark",
+ "tags": ["gdev", "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": "New Features in v6.2",
+ "uid": "ZvPm55mWk",
+ "version": 1
+}
diff --git a/docs/sources/installation/upgrading.md b/docs/sources/installation/upgrading.md
index bd2a5434b25fd..22195cb9df503 100644
--- a/docs/sources/installation/upgrading.md
+++ b/docs/sources/installation/upgrading.md
@@ -169,3 +169,9 @@ configuration.
If you're embedding Grafana in a ``, `
{
);
const gaugeWidthReduceRatio = showThresholdLabels ? 1.5 : 1;
- const gaugeWidth = Math.min(dimension / 5, 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;
diff --git a/packages/grafana-ui/src/components/Graph/GraphLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx
index 451acf4bac805..5b7a0251e0520 100644
--- a/packages/grafana-ui/src/components/Graph/GraphLegend.tsx
+++ b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx
@@ -14,10 +14,10 @@ interface GraphLegendProps extends LegendProps {
displayMode: LegendDisplayMode;
sortBy?: string;
sortDesc?: boolean;
- onSeriesColorChange: SeriesColorChangeHandler;
+ onSeriesColorChange?: SeriesColorChangeHandler;
onSeriesAxisToggle?: SeriesAxisToggleHandler;
- onToggleSort: (sortBy: string) => void;
- onLabelClick: (item: LegendItem, event: React.MouseEvent
) => void;
+ onToggleSort?: (sortBy: string) => void;
+ onLabelClick?: (item: LegendItem, event: React.MouseEvent) => void;
}
export const GraphLegend: React.FunctionComponent = ({
@@ -116,3 +116,5 @@ export const GraphLegend: React.FunctionComponent = ({
/>
);
};
+
+GraphLegend.displayName = 'GraphLegend';
diff --git a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx
index e116287d4d21e..37371fe066442 100644
--- a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx
+++ b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx
@@ -10,9 +10,9 @@ export interface GraphLegendItemProps {
key?: React.Key;
item: LegendItem;
className?: string;
- onLabelClick: (item: LegendItem, event: React.MouseEvent) => void;
- onSeriesColorChange: SeriesColorChangeHandler;
- onToggleAxis: () => void;
+ onLabelClick?: (item: LegendItem, event: React.MouseEvent) => void;
+ onSeriesColorChange?: SeriesColorChangeHandler;
+ onToggleAxis?: () => void;
}
export const GraphLegendListItem: React.FunctionComponent = ({
@@ -21,19 +21,31 @@ export const GraphLegendListItem: React.FunctionComponent
onToggleAxis,
onLabelClick,
}) => {
+ const theme = useContext(ThemeContext);
+
return (
<>
onSeriesColorChange(item.label, color)}
+ onColorChange={color => {
+ if (onSeriesColorChange) {
+ onSeriesColorChange(item.label, color);
+ }
+ }}
onToggleAxis={onToggleAxis}
yAxis={item.yAxis}
/>
onLabelClick(item, event)}
+ onClick={event => {
+ if (onLabelClick) {
+ onLabelClick(item, event);
+ }
+ }}
className={css`
cursor: pointer;
white-space: nowrap;
+ color: ${!item.isVisible && theme.colors.linkDisabled};
`}
>
{item.label}
@@ -74,13 +86,22 @@ export const GraphLegendTableRow: React.FunctionComponent
`}
>
onSeriesColorChange(item.label, color)}
+ onColorChange={color => {
+ if (onSeriesColorChange) {
+ onSeriesColorChange(item.label, color);
+ }
+ }}
onToggleAxis={onToggleAxis}
yAxis={item.yAxis}
/>
onLabelClick(item, event)}
+ onClick={event => {
+ if (onLabelClick) {
+ onLabelClick(item, event);
+ }
+ }}
className={css`
cursor: pointer;
white-space: nowrap;
diff --git a/packages/grafana-ui/src/components/Legend/LegendList.tsx b/packages/grafana-ui/src/components/Legend/LegendList.tsx
index d103aa3ed8067..f220b10a58765 100644
--- a/packages/grafana-ui/src/components/Legend/LegendList.tsx
+++ b/packages/grafana-ui/src/components/Legend/LegendList.tsx
@@ -28,7 +28,7 @@ export const LegendList: React.FunctionComponent
= ({
);
};
- const getItemKey = (item: LegendItem) => item.label;
+ const getItemKey = (item: LegendItem) => `${item.label}`;
const styles = {
wrapper: cx(
diff --git a/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx
index 1913c2e500d25..787b818c00303 100644
--- a/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx
+++ b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx
@@ -1,8 +1,10 @@
import React from 'react';
+import { css, cx } from 'emotion';
import { SeriesColorPicker } from '../ColorPicker/ColorPicker';
-import { SeriesIcon } from './SeriesIcon';
+import { SeriesIcon, SeriesIconProps } from './SeriesIcon';
interface LegendSeriesIconProps {
+ disabled: boolean;
color: string;
yAxis: number;
onColorChange: (color: string) => void;
@@ -10,12 +12,36 @@ interface LegendSeriesIconProps {
}
export const LegendSeriesIcon: React.FunctionComponent = ({
+ disabled,
yAxis,
color,
onColorChange,
onToggleAxis,
}) => {
- return (
+ let iconProps: SeriesIconProps = {
+ color,
+ };
+
+ if (!disabled) {
+ iconProps = {
+ ...iconProps,
+ className: 'pointer',
+ };
+ }
+
+ return disabled ? (
+
+
+
+ ) : (
=
>
{({ ref, showColorPicker, hideColorPicker }) => (
-
+
)}
diff --git a/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx
index 091d79f7fd0d0..70709a0fcd5cf 100644
--- a/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx
+++ b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx
@@ -1,5 +1,10 @@
import React from 'react';
+import { cx } from 'emotion';
-export const SeriesIcon: React.FunctionComponent<{ color: string }> = ({ color }) => {
- return ;
+export interface SeriesIconProps {
+ color: string;
+ className?: string;
+}
+export const SeriesIcon: React.FunctionComponent = ({ color, className }) => {
+ return ;
};
diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts
index 5a4f58626c6a7..860dd5a97ab0e 100644
--- a/packages/grafana-ui/src/components/index.ts
+++ b/packages/grafana-ui/src/components/index.ts
@@ -45,10 +45,20 @@ export { TableInputCSV } from './Table/TableInputCSV';
export { BigValue } from './BigValue/BigValue';
export { Gauge } from './Gauge/Gauge';
export { Graph } from './Graph/Graph';
+export { GraphLegend } from './Graph/GraphLegend';
export { GraphWithLegend } from './Graph/GraphWithLegend';
export { BarGauge } from './BarGauge/BarGauge';
export { VizRepeater } from './VizRepeater/VizRepeater';
-export { LegendOptions, LegendBasicOptions, LegendRenderOptions, LegendList, LegendTable } from './Legend/Legend';
+export {
+ LegendOptions,
+ LegendBasicOptions,
+ LegendRenderOptions,
+ LegendList,
+ LegendTable,
+ LegendItem,
+ LegendPlacement,
+ LegendDisplayMode,
+} from './Legend/Legend';
// Panel editors
export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
export { ClickOutsideWrapper } from './ClickOutsideWrapper/ClickOutsideWrapper';
diff --git a/packages/grafana-ui/src/types/data.ts b/packages/grafana-ui/src/types/data.ts
index e629e76043a75..d1a1a78577761 100644
--- a/packages/grafana-ui/src/types/data.ts
+++ b/packages/grafana-ui/src/types/data.ts
@@ -47,7 +47,6 @@ export interface Field {
unit?: string;
dateFormat?: string; // Source data format
decimals?: number | null; // Significant digits (for display)
- color?: string;
min?: number | null;
max?: number | null;
}
diff --git a/packages/grafana-ui/src/types/plugin.ts b/packages/grafana-ui/src/types/plugin.ts
index c083fd95be381..72e9d2453fd50 100644
--- a/packages/grafana-ui/src/types/plugin.ts
+++ b/packages/grafana-ui/src/types/plugin.ts
@@ -91,17 +91,17 @@ export interface PluginMetaInfo {
version: string;
}
-export interface PluginConfigTabProps {
- meta: T;
+export interface PluginConfigPageProps {
+ plugin: T;
query: { [s: string]: any }; // The URL query parameters
}
-export interface PluginConfigTab {
+export interface PluginConfigPage {
title: string; // Display
icon?: string;
id: string; // Unique, in URL
- body: ComponentClass>;
+ body: ComponentClass>;
}
export class GrafanaPlugin {
@@ -112,14 +112,14 @@ export class GrafanaPlugin {
angularConfigCtrl?: any;
// Show configuration tabs on the plugin page
- configTabs?: Array>;
+ configPages?: Array>;
// Tabs on the plugin page
- addConfigTab(tab: PluginConfigTab) {
- if (!this.configTabs) {
- this.configTabs = [];
+ addConfigPage(tab: PluginConfigPage) {
+ if (!this.configPages) {
+ this.configPages = [];
}
- this.configTabs.push(tab);
+ this.configPages.push(tab);
return this;
}
}
diff --git a/packages/grafana-ui/src/utils/displayValue.test.ts b/packages/grafana-ui/src/utils/displayValue.test.ts
index 63c78e9798262..139286acc0172 100644
--- a/packages/grafana-ui/src/utils/displayValue.test.ts
+++ b/packages/grafana-ui/src/utils/displayValue.test.ts
@@ -18,7 +18,7 @@ describe('Process simple display values', () => {
getDisplayProcessor(),
// Add a simple option that is not used (uses a different base class)
- getDisplayProcessor({ field: { color: '#FFF' } }),
+ getDisplayProcessor({ field: { min: 0, max: 100 } }),
// Add a simple option that is not used (uses a different base class)
getDisplayProcessor({ field: { unit: 'locale' } }),
diff --git a/packages/grafana-ui/src/utils/displayValue.ts b/packages/grafana-ui/src/utils/displayValue.ts
index 59a04fefc2b93..6565985f44515 100644
--- a/packages/grafana-ui/src/utils/displayValue.ts
+++ b/packages/grafana-ui/src/utils/displayValue.ts
@@ -42,7 +42,7 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce
return (value: any) => {
const { mappings, thresholds, theme } = options;
- let color = field.color;
+ let color;
let text = _.toString(value);
let numeric = toNumber(value);
@@ -76,7 +76,7 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce
const { decimals, scaledDecimals } = getDecimalsForValue(value, field.decimals);
text = formatFunc(numeric, decimals, scaledDecimals, options.isUtc);
}
- if (thresholds && thresholds.length > 0) {
+ if (thresholds && thresholds.length) {
color = getColorFromThreshold(numeric, thresholds, theme);
}
}
diff --git a/pkg/cmd/grafana-cli/utils/grafana_path.go b/pkg/cmd/grafana-cli/utils/grafana_path.go
index 5f5c944f52b5b..956a8c26b5964 100644
--- a/pkg/cmd/grafana-cli/utils/grafana_path.go
+++ b/pkg/cmd/grafana-cli/utils/grafana_path.go
@@ -2,36 +2,41 @@ package utils
import (
"os"
+ "path"
+ "path/filepath"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
)
func GetGrafanaPluginDir(currentOS string) string {
- //currentOS := runtime.GOOS
-
- if currentOS == "windows" {
- return returnOsDefault(currentOS)
- }
-
- pwd, err := os.Getwd()
-
- if err != nil {
- logger.Error("Could not get current path. using default")
- return returnOsDefault(currentOS)
- }
-
- if isDevenvironment(pwd) {
+ if isDevEnvironment() {
return "../data/plugins"
}
return returnOsDefault(currentOS)
}
-func isDevenvironment(pwd string) bool {
+func isDevEnvironment() bool {
// if ../conf/defaults.ini exists, grafana is not installed as package
// that its in development environment.
- _, err := os.Stat("../conf/defaults.ini")
- return err == nil
+ ex, err := os.Executable()
+ if err != nil {
+ logger.Error("Could not get executable path. Assuming non dev environment.")
+ return false
+ }
+ exPath := filepath.Dir(ex)
+ _, last := path.Split(exPath)
+ if last == "bin" {
+ // In dev env the executable for current platform is created in 'bin/' dir
+ defaultsPath := filepath.Join(exPath, "../conf/defaults.ini")
+ _, err = os.Stat(defaultsPath)
+ return err == nil
+ } else {
+ // But at the same time there are per platform directories that contain the binaries and can also be used.
+ defaultsPath := filepath.Join(exPath, "../../conf/defaults.ini")
+ _, err = os.Stat(defaultsPath)
+ return err == nil
+ }
}
func returnOsDefault(currentOs string) string {
diff --git a/pkg/infra/serverlock/serverlock_integration_test.go b/pkg/infra/serverlock/serverlock_integration_test.go
index 8bcd9c2ca2563..60c3cf17875d5 100644
--- a/pkg/infra/serverlock/serverlock_integration_test.go
+++ b/pkg/infra/serverlock/serverlock_integration_test.go
@@ -7,34 +7,29 @@ import (
"testing"
"time"
- . "github.com/smartystreets/goconvey/convey"
+ "github.com/stretchr/testify/assert"
)
func TestServerLok(t *testing.T) {
sl := createTestableServerLock(t)
- Convey("Server lock integration tests", t, func() {
- counter := 0
- var err error
- incCounter := func() { counter++ }
- atInterval := time.Second * 1
- ctx := context.Background()
-
- //this time `fn` should be executed
- So(sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter), ShouldBeNil)
-
- //this should not execute `fn`
- So(sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter), ShouldBeNil)
- So(sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter), ShouldBeNil)
- So(sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter), ShouldBeNil)
- So(sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter), ShouldBeNil)
-
- // wait 5 second.
- <-time.After(atInterval * 2)
-
- // now `fn` should be executed again
- err = sl.LockAndExecute(ctx, "test-operation", atInterval, incCounter)
- So(err, ShouldBeNil)
- So(counter, ShouldEqual, 2)
- })
+ counter := 0
+ fn := func() { counter++ }
+ atInterval := time.Second * 1
+ ctx := context.Background()
+
+ //this time `fn` should be executed
+ assert.Nil(t, sl.LockAndExecute(ctx, "test-operation", atInterval, fn))
+
+ //this should not execute `fn`
+ assert.Nil(t, sl.LockAndExecute(ctx, "test-operation", atInterval, fn))
+ assert.Nil(t, sl.LockAndExecute(ctx, "test-operation", atInterval, fn))
+
+ // wait 2 second.
+ <-time.After(time.Second * 2)
+
+ // now `fn` should be executed again
+ err := sl.LockAndExecute(ctx, "test-operation", atInterval, fn)
+ assert.Nil(t, err)
+ assert.Equal(t, counter, 2)
}
diff --git a/pkg/middleware/auth_proxy.go b/pkg/middleware/auth_proxy.go
index 6dc69dda8b5f8..d3d8d8e77d8aa 100644
--- a/pkg/middleware/auth_proxy.go
+++ b/pkg/middleware/auth_proxy.go
@@ -20,17 +20,17 @@ func initContextWithAuthProxy(store *remotecache.RemoteCache, ctx *m.ReqContext,
})
// Bail if auth proxy is not enabled
- if auth.IsEnabled() == false {
+ if !auth.IsEnabled() {
return false
}
// If the there is no header - we can't move forward
- if auth.HasHeader() == false {
+ if !auth.HasHeader() {
return false
}
// Check if allowed to continue with this IP
- if result, err := auth.IsAllowedIP(); result == false {
+ if result, err := auth.IsAllowedIP(); !result {
ctx.Handle(407, err.Error(), err.DetailsError)
return true
}
diff --git a/pkg/middleware/auth_proxy/auth_proxy.go b/pkg/middleware/auth_proxy/auth_proxy.go
index b9e71d1b480d4..98bacbeccf47f 100644
--- a/pkg/middleware/auth_proxy/auth_proxy.go
+++ b/pkg/middleware/auth_proxy/auth_proxy.go
@@ -92,7 +92,7 @@ func New(options *Options) *AuthProxy {
func (auth *AuthProxy) IsEnabled() bool {
// Bail if the setting is not enabled
- if auth.enabled == false {
+ if !auth.enabled {
return false
}
diff --git a/pkg/services/alerting/commands.go b/pkg/services/alerting/commands.go
index dd2ff5658d60c..887334ec7290b 100644
--- a/pkg/services/alerting/commands.go
+++ b/pkg/services/alerting/commands.go
@@ -2,7 +2,7 @@ package alerting
import (
"github.com/grafana/grafana/pkg/bus"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
func init() {
@@ -10,14 +10,14 @@ func init() {
bus.AddHandler("alerting", validateDashboardAlerts)
}
-func validateDashboardAlerts(cmd *m.ValidateDashboardAlertsCommand) error {
+func validateDashboardAlerts(cmd *models.ValidateDashboardAlertsCommand) error {
extractor := NewDashAlertExtractor(cmd.Dashboard, cmd.OrgId, cmd.User)
return extractor.ValidateAlerts()
}
-func updateDashboardAlerts(cmd *m.UpdateDashboardAlertsCommand) error {
- saveAlerts := m.SaveAlertsCommand{
+func updateDashboardAlerts(cmd *models.UpdateDashboardAlertsCommand) error {
+ saveAlerts := models.SaveAlertsCommand{
OrgId: cmd.OrgId,
UserId: cmd.User.UserId,
DashboardId: cmd.Dashboard.Id,
diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go
index 7d1a276c42e64..37dbd9b3f7a69 100644
--- a/pkg/services/alerting/conditions/query.go
+++ b/pkg/services/alerting/conditions/query.go
@@ -10,7 +10,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/tsdb"
)
@@ -100,7 +100,7 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
}
func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *tsdb.TimeRange) (tsdb.TimeSeriesSlice, error) {
- getDsInfo := &m.GetDataSourceByIdQuery{
+ getDsInfo := &models.GetDataSourceByIdQuery{
Id: c.Query.DatasourceId,
OrgId: context.Rule.OrgId,
}
@@ -139,7 +139,7 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange *
return result, nil
}
-func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource, timeRange *tsdb.TimeRange) *tsdb.TsdbQuery {
+func (c *QueryCondition) getRequestForAlertRule(datasource *models.DataSource, timeRange *tsdb.TimeRange) *tsdb.TsdbQuery {
req := &tsdb.TsdbQuery{
TimeRange: timeRange,
Queries: []*tsdb.Query{
diff --git a/pkg/services/alerting/conditions/query_test.go b/pkg/services/alerting/conditions/query_test.go
index 0ea6470bc2d80..2e1ecf5f39c53 100644
--- a/pkg/services/alerting/conditions/query_test.go
+++ b/pkg/services/alerting/conditions/query_test.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/tsdb"
. "github.com/smartystreets/goconvey/convey"
@@ -168,7 +168,7 @@ func (ctx *queryConditionTestContext) exec() (*alerting.ConditionResult, error)
ctx.condition = condition
- condition.HandleRequest = func(context context.Context, dsInfo *m.DataSource, req *tsdb.TsdbQuery) (*tsdb.Response, error) {
+ condition.HandleRequest = func(context context.Context, dsInfo *models.DataSource, req *tsdb.TsdbQuery) (*tsdb.Response, error) {
return &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
"A": {Series: ctx.series},
@@ -182,8 +182,8 @@ func (ctx *queryConditionTestContext) exec() (*alerting.ConditionResult, error)
func queryConditionScenario(desc string, fn queryConditionScenarioFunc) {
Convey(desc, func() {
- bus.AddHandler("test", func(query *m.GetDataSourceByIdQuery) error {
- query.Result = &m.DataSource{Id: 1, Type: "graphite"}
+ bus.AddHandler("test", func(query *models.GetDataSourceByIdQuery) error {
+ query.Result = &models.DataSource{Id: 1, Type: "graphite"}
return nil
})
diff --git a/pkg/services/alerting/eval_context.go b/pkg/services/alerting/eval_context.go
index 6358c22a97f1c..7d9a9014086b5 100644
--- a/pkg/services/alerting/eval_context.go
+++ b/pkg/services/alerting/eval_context.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
@@ -23,12 +23,12 @@ type EvalContext struct {
Rule *Rule
log log.Logger
- dashboardRef *m.DashboardRef
+ dashboardRef *models.DashboardRef
ImagePublicUrl string
ImageOnDiskPath string
NoDataFound bool
- PrevAlertState m.AlertStateType
+ PrevAlertState models.AlertStateType
Ctx context.Context
}
@@ -53,22 +53,22 @@ type StateDescription struct {
func (c *EvalContext) GetStateModel() *StateDescription {
switch c.Rule.State {
- case m.AlertStateOK:
+ case models.AlertStateOK:
return &StateDescription{
Color: "#36a64f",
Text: "OK",
}
- case m.AlertStateNoData:
+ case models.AlertStateNoData:
return &StateDescription{
Color: "#888888",
Text: "No Data",
}
- case m.AlertStateAlerting:
+ case models.AlertStateAlerting:
return &StateDescription{
Color: "#D63232",
Text: "Alerting",
}
- case m.AlertStateUnknown:
+ case models.AlertStateUnknown:
return &StateDescription{
Color: "#888888",
Text: "Unknown",
@@ -90,12 +90,12 @@ func (c *EvalContext) GetNotificationTitle() string {
return "[" + c.GetStateModel().Text + "] " + c.Rule.Name
}
-func (c *EvalContext) GetDashboardUID() (*m.DashboardRef, error) {
+func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
if c.dashboardRef != nil {
return c.dashboardRef, nil
}
- uidQuery := &m.GetDashboardRefByIdQuery{Id: c.Rule.DashboardId}
+ uidQuery := &models.GetDashboardRefByIdQuery{Id: c.Rule.DashboardId}
if err := bus.Dispatch(uidQuery); err != nil {
return nil, err
}
@@ -115,29 +115,29 @@ func (c *EvalContext) GetRuleUrl() (string, error) {
if err != nil {
return "", err
}
- return fmt.Sprintf(urlFormat, m.GetFullDashboardUrl(ref.Uid, ref.Slug), c.Rule.PanelId, c.Rule.OrgId), nil
+ return fmt.Sprintf(urlFormat, models.GetFullDashboardUrl(ref.Uid, ref.Slug), c.Rule.PanelId, c.Rule.OrgId), nil
}
// GetNewState returns the new state from the alert rule evaluation
-func (c *EvalContext) GetNewState() m.AlertStateType {
+func (c *EvalContext) GetNewState() models.AlertStateType {
ns := getNewStateInternal(c)
- if ns != m.AlertStateAlerting || c.Rule.For == 0 {
+ if ns != models.AlertStateAlerting || c.Rule.For == 0 {
return ns
}
since := time.Since(c.Rule.LastStateChange)
- if c.PrevAlertState == m.AlertStatePending && since > c.Rule.For {
- return m.AlertStateAlerting
+ if c.PrevAlertState == models.AlertStatePending && since > c.Rule.For {
+ return models.AlertStateAlerting
}
- if c.PrevAlertState == m.AlertStateAlerting {
- return m.AlertStateAlerting
+ if c.PrevAlertState == models.AlertStateAlerting {
+ return models.AlertStateAlerting
}
- return m.AlertStatePending
+ return models.AlertStatePending
}
-func getNewStateInternal(c *EvalContext) m.AlertStateType {
+func getNewStateInternal(c *EvalContext) models.AlertStateType {
if c.Error != nil {
c.log.Error("Alert Rule Result Error",
"ruleId", c.Rule.Id,
@@ -145,14 +145,14 @@ func getNewStateInternal(c *EvalContext) m.AlertStateType {
"error", c.Error,
"changing state to", c.Rule.ExecutionErrorState.ToAlertState())
- if c.Rule.ExecutionErrorState == m.ExecutionErrorKeepState {
+ if c.Rule.ExecutionErrorState == models.ExecutionErrorKeepState {
return c.PrevAlertState
}
return c.Rule.ExecutionErrorState.ToAlertState()
}
if c.Firing {
- return m.AlertStateAlerting
+ return models.AlertStateAlerting
}
if c.NoDataFound {
@@ -161,11 +161,11 @@ func getNewStateInternal(c *EvalContext) m.AlertStateType {
"name", c.Rule.Name,
"changing state to", c.Rule.NoDataState.ToAlertState())
- if c.Rule.NoDataState == m.NoDataKeepState {
+ if c.Rule.NoDataState == models.NoDataKeepState {
return c.PrevAlertState
}
return c.Rule.NoDataState.ToAlertState()
}
- return m.AlertStateOK
+ return models.AlertStateOK
}
diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go
index c3fcc01ad55e2..6bf5e786c1982 100644
--- a/pkg/services/alerting/extractor.go
+++ b/pkg/services/alerting/extractor.go
@@ -8,19 +8,19 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
// DashAlertExtractor extracts alerts from the dashboard json
type DashAlertExtractor struct {
- User *m.SignedInUser
- Dash *m.Dashboard
+ User *models.SignedInUser
+ Dash *models.Dashboard
OrgID int64
log log.Logger
}
// NewDashAlertExtractor returns a new DashAlertExtractor
-func NewDashAlertExtractor(dash *m.Dashboard, orgID int64, user *m.SignedInUser) *DashAlertExtractor {
+func NewDashAlertExtractor(dash *models.Dashboard, orgID int64, user *models.SignedInUser) *DashAlertExtractor {
return &DashAlertExtractor{
User: user,
Dash: dash,
@@ -29,9 +29,9 @@ func NewDashAlertExtractor(dash *m.Dashboard, orgID int64, user *m.SignedInUser)
}
}
-func (e *DashAlertExtractor) lookupDatasourceID(dsName string) (*m.DataSource, error) {
+func (e *DashAlertExtractor) lookupDatasourceID(dsName string) (*models.DataSource, error) {
if dsName == "" {
- query := &m.GetDataSourcesQuery{OrgId: e.OrgID}
+ query := &models.GetDataSourcesQuery{OrgId: e.OrgID}
if err := bus.Dispatch(query); err != nil {
return nil, err
}
@@ -42,7 +42,7 @@ func (e *DashAlertExtractor) lookupDatasourceID(dsName string) (*m.DataSource, e
}
}
} else {
- query := &m.GetDataSourceByNameQuery{Name: dsName, OrgId: e.OrgID}
+ query := &models.GetDataSourceByNameQuery{Name: dsName, OrgId: e.OrgID}
if err := bus.Dispatch(query); err != nil {
return nil, err
}
@@ -73,8 +73,8 @@ func copyJSON(in *simplejson.Json) (*simplejson.Json, error) {
return simplejson.NewJson(rawJSON)
}
-func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, validateAlertFunc func(*m.Alert) bool) ([]*m.Alert, error) {
- alerts := make([]*m.Alert, 0)
+func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, validateAlertFunc func(*models.Alert) bool) ([]*models.Alert, error) {
+ alerts := make([]*models.Alert, 0)
for _, panelObj := range jsonWithPanels.Get("panels").MustArray() {
panel := simplejson.NewFromAny(panelObj)
@@ -124,7 +124,7 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json,
}
}
- alert := &m.Alert{
+ alert := &models.Alert{
DashboardId: e.Dash.Id,
OrgId: e.OrgID,
PanelId: panelID,
@@ -161,9 +161,9 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json,
return nil, ValidationError{Reason: fmt.Sprintf("Data source used by alert rule not found, alertName=%v, datasource=%s", alert.Name, dsName)}
}
- dsFilterQuery := m.DatasourcesPermissionFilterQuery{
+ dsFilterQuery := models.DatasourcesPermissionFilterQuery{
User: e.User,
- Datasources: []*m.DataSource{datasource},
+ Datasources: []*models.DataSource{datasource},
}
if err := bus.Dispatch(&dsFilterQuery); err != nil {
@@ -172,7 +172,7 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json,
}
} else {
if len(dsFilterQuery.Result) == 0 {
- return nil, m.ErrDataSourceAccessDenied
+ return nil, models.ErrDataSourceAccessDenied
}
}
@@ -203,22 +203,22 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json,
return alerts, nil
}
-func validateAlertRule(alert *m.Alert) bool {
+func validateAlertRule(alert *models.Alert) bool {
return alert.ValidToSave()
}
// GetAlerts extracts alerts from the dashboard json and does full validation on the alert json data
-func (e *DashAlertExtractor) GetAlerts() ([]*m.Alert, error) {
+func (e *DashAlertExtractor) GetAlerts() ([]*models.Alert, error) {
return e.extractAlerts(validateAlertRule)
}
-func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *m.Alert) bool) ([]*m.Alert, error) {
+func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *models.Alert) bool) ([]*models.Alert, error) {
dashboardJSON, err := copyJSON(e.Dash.Data)
if err != nil {
return nil, err
}
- alerts := make([]*m.Alert, 0)
+ alerts := make([]*models.Alert, 0)
// We extract alerts from rows to be backwards compatible
// with the old dashboard json model.
@@ -249,6 +249,6 @@ func (e *DashAlertExtractor) extractAlerts(validateFunc func(alert *m.Alert) boo
// ValidateAlerts validates alerts in the dashboard json but does not require a valid dashboard id
// in the first validation pass
func (e *DashAlertExtractor) ValidateAlerts() error {
- _, err := e.extractAlerts(func(alert *m.Alert) bool { return alert.OrgId != 0 && alert.PanelId != 0 })
+ _, err := e.extractAlerts(func(alert *models.Alert) bool { return alert.OrgId != 0 && alert.PanelId != 0 })
return err
}
diff --git a/pkg/services/alerting/extractor_test.go b/pkg/services/alerting/extractor_test.go
index 9c689fec921b6..716ff746cd84b 100644
--- a/pkg/services/alerting/extractor_test.go
+++ b/pkg/services/alerting/extractor_test.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,17 +21,17 @@ func TestAlertRuleExtraction(t *testing.T) {
})
// mock data
- defaultDs := &m.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true}
- graphite2Ds := &m.DataSource{Id: 15, OrgId: 1, Name: "graphite2"}
- influxDBDs := &m.DataSource{Id: 16, OrgId: 1, Name: "InfluxDB"}
- prom := &m.DataSource{Id: 17, OrgId: 1, Name: "Prometheus"}
+ defaultDs := &models.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true}
+ graphite2Ds := &models.DataSource{Id: 15, OrgId: 1, Name: "graphite2"}
+ influxDBDs := &models.DataSource{Id: 16, OrgId: 1, Name: "InfluxDB"}
+ prom := &models.DataSource{Id: 17, OrgId: 1, Name: "Prometheus"}
- bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error {
- query.Result = []*m.DataSource{defaultDs, graphite2Ds}
+ bus.AddHandler("test", func(query *models.GetDataSourcesQuery) error {
+ query.Result = []*models.DataSource{defaultDs, graphite2Ds}
return nil
})
- bus.AddHandler("test", func(query *m.GetDataSourceByNameQuery) error {
+ bus.AddHandler("test", func(query *models.GetDataSourceByNameQuery) error {
if query.Name == defaultDs.Name {
query.Result = defaultDs
}
@@ -55,7 +55,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
getTarget := func(j *simplejson.Json) string {
rowObj := j.Get("rows").MustArray()[0]
@@ -84,7 +84,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@@ -152,7 +152,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(panelWithoutId)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
_, err = extractor.GetAlerts()
@@ -168,7 +168,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(panelWithIdZero)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
_, err = extractor.GetAlerts()
@@ -184,7 +184,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@@ -200,10 +200,10 @@ func TestAlertRuleExtraction(t *testing.T) {
Convey("Alert notifications are in DB", func() {
sqlstore.InitTestDB(t)
- firstNotification := m.CreateAlertNotificationCommand{Uid: "notifier1", OrgId: 1, Name: "1"}
+ firstNotification := models.CreateAlertNotificationCommand{Uid: "notifier1", OrgId: 1, Name: "1"}
err = sqlstore.CreateAlertNotificationCommand(&firstNotification)
So(err, ShouldBeNil)
- secondNotification := m.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
+ secondNotification := models.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
err = sqlstore.CreateAlertNotificationCommand(&secondNotification)
So(err, ShouldBeNil)
@@ -213,7 +213,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@@ -243,7 +243,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJson)
+ dash := models.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1, nil)
alerts, err := extractor.GetAlerts()
@@ -263,7 +263,7 @@ func TestAlertRuleExtraction(t *testing.T) {
dashJSON, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
- dash := m.NewDashboardFromJson(dashJSON)
+ dash := models.NewDashboardFromJson(dashJSON)
extractor := NewDashAlertExtractor(dash, 1, nil)
err = extractor.ValidateAlerts()
diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go
index 8c2ac839e439b..a2824da4a67c6 100644
--- a/pkg/services/alerting/notifier.go
+++ b/pkg/services/alerting/notifier.go
@@ -8,10 +8,9 @@ import (
"github.com/grafana/grafana/pkg/components/imguploader"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting"
-
- m "github.com/grafana/grafana/pkg/models"
)
type NotifierPlugin struct {
@@ -73,7 +72,7 @@ func (n *notificationService) sendAndMarkAsComplete(evalContext *EvalContext, no
return nil
}
- cmd := &m.SetAlertNotificationStateToCompleteCommand{
+ cmd := &models.SetAlertNotificationStateToCompleteCommand{
Id: notifierState.state.Id,
Version: notifierState.state.Version,
}
@@ -83,14 +82,14 @@ func (n *notificationService) sendAndMarkAsComplete(evalContext *EvalContext, no
func (n *notificationService) sendNotification(evalContext *EvalContext, notifierState *notifierState) error {
if !evalContext.IsTestRun {
- setPendingCmd := &m.SetAlertNotificationStateToPendingCommand{
+ setPendingCmd := &models.SetAlertNotificationStateToPendingCommand{
Id: notifierState.state.Id,
Version: notifierState.state.Version,
AlertRuleStateUpdatedVersion: evalContext.Rule.StateChanges,
}
err := bus.DispatchCtx(evalContext.Ctx, setPendingCmd)
- if err == m.ErrAlertNotificationStateVersionConflict {
+ if err == models.ErrAlertNotificationStateVersionConflict {
return nil
}
@@ -128,7 +127,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
Height: 500,
Timeout: setting.AlertingEvaluationTimeout,
OrgId: context.Rule.OrgId,
- OrgRole: m.ROLE_ADMIN,
+ OrgRole: models.ROLE_ADMIN,
ConcurrentLimit: setting.AlertingRenderLimit,
}
@@ -158,7 +157,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) {
}
func (n *notificationService) getNeededNotifiers(orgId int64, notificationUids []string, evalContext *EvalContext) (notifierStateSlice, error) {
- query := &m.GetAlertNotificationsWithUidToSendQuery{OrgId: orgId, Uids: notificationUids}
+ query := &models.GetAlertNotificationsWithUidToSendQuery{OrgId: orgId, Uids: notificationUids}
if err := bus.Dispatch(query); err != nil {
return nil, err
@@ -172,7 +171,7 @@ func (n *notificationService) getNeededNotifiers(orgId int64, notificationUids [
continue
}
- query := &m.GetOrCreateNotificationStateQuery{
+ query := &models.GetOrCreateNotificationStateQuery{
NotifierId: notification.Id,
AlertId: evalContext.Rule.Id,
OrgId: evalContext.Rule.OrgId,
@@ -196,7 +195,7 @@ func (n *notificationService) getNeededNotifiers(orgId int64, notificationUids [
}
// InitNotifier instantiate a new notifier based on the model
-func InitNotifier(model *m.AlertNotification) (Notifier, error) {
+func InitNotifier(model *models.AlertNotification) (Notifier, error) {
notifierPlugin, found := notifierFactories[model.Type]
if !found {
return nil, errors.New("Unsupported notification type")
@@ -205,7 +204,7 @@ func InitNotifier(model *m.AlertNotification) (Notifier, error) {
return notifierPlugin.Factory(model)
}
-type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)
+type NotifierFactory func(notification *models.AlertNotification) (Notifier, error)
var notifierFactories = make(map[string]*NotifierPlugin)
diff --git a/pkg/services/alerting/notifiers/alertmanager.go b/pkg/services/alerting/notifiers/alertmanager.go
index 9febe42505be3..b90f9e65792c7 100644
--- a/pkg/services/alerting/notifiers/alertmanager.go
+++ b/pkg/services/alerting/notifiers/alertmanager.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -27,7 +27,7 @@ func init() {
})
}
-func NewAlertmanagerNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewAlertmanagerNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -46,24 +46,24 @@ type AlertmanagerNotifier struct {
log log.Logger
}
-func (this *AlertmanagerNotifier) ShouldNotify(ctx context.Context, evalContext *alerting.EvalContext, notificationState *m.AlertNotificationState) bool {
+func (this *AlertmanagerNotifier) ShouldNotify(ctx context.Context, evalContext *alerting.EvalContext, notificationState *models.AlertNotificationState) bool {
this.log.Debug("Should notify", "ruleId", evalContext.Rule.Id, "state", evalContext.Rule.State, "previousState", evalContext.PrevAlertState)
// Do not notify when we become OK for the first time.
- if (evalContext.PrevAlertState == m.AlertStatePending) && (evalContext.Rule.State == m.AlertStateOK) {
+ if (evalContext.PrevAlertState == models.AlertStatePending) && (evalContext.Rule.State == models.AlertStateOK) {
return false
}
// Notify on Alerting -> OK to resolve before alertmanager timeout.
- if (evalContext.PrevAlertState == m.AlertStateAlerting) && (evalContext.Rule.State == m.AlertStateOK) {
+ if (evalContext.PrevAlertState == models.AlertStateAlerting) && (evalContext.Rule.State == models.AlertStateOK) {
return true
}
- return evalContext.Rule.State == m.AlertStateAlerting
+ return evalContext.Rule.State == models.AlertStateAlerting
}
func (this *AlertmanagerNotifier) createAlert(evalContext *alerting.EvalContext, match *alerting.EvalMatch, ruleUrl string) *simplejson.Json {
alertJSON := simplejson.New()
alertJSON.Set("startsAt", evalContext.StartTime.UTC().Format(time.RFC3339))
- if evalContext.Rule.State == m.AlertStateOK {
+ if evalContext.Rule.State == models.AlertStateOK {
alertJSON.Set("endsAt", time.Now().UTC().Format(time.RFC3339))
}
alertJSON.Set("generatorURL", ruleUrl)
@@ -128,7 +128,7 @@ func (this *AlertmanagerNotifier) Notify(evalContext *alerting.EvalContext) erro
bodyJSON := simplejson.NewFromAny(alerts)
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.Url + "/api/v1/alerts",
HttpMethod: "POST",
Body: string(body),
diff --git a/pkg/services/alerting/notifiers/alertmanager_test.go b/pkg/services/alerting/notifiers/alertmanager_test.go
index 9197926035ea8..acf039fbf68ee 100644
--- a/pkg/services/alerting/notifiers/alertmanager_test.go
+++ b/pkg/services/alerting/notifiers/alertmanager_test.go
@@ -6,36 +6,37 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
+
"github.com/grafana/grafana/pkg/services/alerting"
. "github.com/smartystreets/goconvey/convey"
)
func TestWhenAlertManagerShouldNotify(t *testing.T) {
tcs := []struct {
- prevState m.AlertStateType
- newState m.AlertStateType
+ prevState models.AlertStateType
+ newState models.AlertStateType
expect bool
}{
{
- prevState: m.AlertStatePending,
- newState: m.AlertStateOK,
+ prevState: models.AlertStatePending,
+ newState: models.AlertStateOK,
expect: false,
},
{
- prevState: m.AlertStateAlerting,
- newState: m.AlertStateOK,
+ prevState: models.AlertStateAlerting,
+ newState: models.AlertStateOK,
expect: true,
},
{
- prevState: m.AlertStateOK,
- newState: m.AlertStatePending,
+ prevState: models.AlertStateOK,
+ newState: models.AlertStatePending,
expect: false,
},
{
- prevState: m.AlertStateUnknown,
- newState: m.AlertStatePending,
+ prevState: models.AlertStateUnknown,
+ newState: models.AlertStatePending,
expect: false,
},
}
@@ -48,7 +49,7 @@ func TestWhenAlertManagerShouldNotify(t *testing.T) {
evalContext.Rule.State = tc.newState
- res := am.ShouldNotify(context.TODO(), evalContext, &m.AlertNotificationState{})
+ res := am.ShouldNotify(context.TODO(), evalContext, &models.AlertNotificationState{})
if res != tc.expect {
t.Errorf("got %v expected %v", res, tc.expect)
}
@@ -63,7 +64,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "alertmanager",
Type: "alertmanager",
Settings: settingsJSON,
@@ -77,7 +78,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
json := `{ "url": "http://127.0.0.1:9093/" }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "alertmanager",
Type: "alertmanager",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/dingding.go b/pkg/services/alerting/notifiers/dingding.go
index 0aa2ba078f37b..45ce24c9aaa14 100644
--- a/pkg/services/alerting/notifiers/dingding.go
+++ b/pkg/services/alerting/notifiers/dingding.go
@@ -8,7 +8,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -36,7 +36,7 @@ func init() {
}
-func NewDingDingNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewDingDingNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -129,7 +129,7 @@ func (this *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error {
return err
}
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.Url,
Body: string(body),
}
diff --git a/pkg/services/alerting/notifiers/dingding_test.go b/pkg/services/alerting/notifiers/dingding_test.go
index f89bf6382ce98..7d645d7efb626 100644
--- a/pkg/services/alerting/notifiers/dingding_test.go
+++ b/pkg/services/alerting/notifiers/dingding_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -14,7 +14,7 @@ func TestDingDingNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "dingding_testing",
Type: "dingding",
Settings: settingsJSON,
@@ -28,7 +28,7 @@ func TestDingDingNotifier(t *testing.T) {
json := `{ "url": "https://www.google.com" }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "dingding_testing",
Type: "dingding",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/discord.go b/pkg/services/alerting/notifiers/discord.go
index 6ed422b1cbb09..9933ad5e5871f 100644
--- a/pkg/services/alerting/notifiers/discord.go
+++ b/pkg/services/alerting/notifiers/discord.go
@@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
@@ -32,7 +32,7 @@ func init() {
})
}
-func NewDiscordNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewDiscordNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find webhook url property in settings"}
@@ -111,7 +111,7 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
json, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.WebhookURL,
HttpMethod: "POST",
ContentType: "application/json",
@@ -135,7 +135,7 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
return nil
}
-func (this *DiscordNotifier) embedImage(cmd *m.SendWebhookSync, imagePath string, existingJSONBody []byte) error {
+func (this *DiscordNotifier) embedImage(cmd *models.SendWebhookSync, imagePath string, existingJSONBody []byte) error {
f, err := os.Open(imagePath)
defer f.Close()
if err != nil {
diff --git a/pkg/services/alerting/notifiers/discord_test.go b/pkg/services/alerting/notifiers/discord_test.go
index fe925aab362ec..dfc6bbe9aee09 100644
--- a/pkg/services/alerting/notifiers/discord_test.go
+++ b/pkg/services/alerting/notifiers/discord_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestDiscordNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "discord_testing",
Type: "discord",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestDiscordNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "discord_testing",
Type: "discord",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go
index b3f465a2b80ce..61b7b11d893ca 100644
--- a/pkg/services/alerting/notifiers/email.go
+++ b/pkg/services/alerting/notifiers/email.go
@@ -6,7 +6,8 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
+
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
@@ -35,7 +36,7 @@ type EmailNotifier struct {
log log.Logger
}
-func NewEmailNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
addressesString := model.Settings.Get("addresses").MustString()
if addressesString == "" {
@@ -72,8 +73,8 @@ func (this *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
error = evalContext.Error.Error()
}
- cmd := &m.SendEmailCommandSync{
- SendEmailCommand: m.SendEmailCommand{
+ cmd := &models.SendEmailCommandSync{
+ SendEmailCommand: models.SendEmailCommand{
Subject: evalContext.GetNotificationTitle(),
Data: map[string]interface{}{
"Title": evalContext.GetNotificationTitle(),
diff --git a/pkg/services/alerting/notifiers/email_test.go b/pkg/services/alerting/notifiers/email_test.go
index 9750cbc2833c2..b0c57f2f254df 100644
--- a/pkg/services/alerting/notifiers/email_test.go
+++ b/pkg/services/alerting/notifiers/email_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestEmailNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestEmailNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
@@ -57,7 +57,7 @@ func TestEmailNotifier(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(json))
So(err, ShouldBeNil)
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "email",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/googlechat.go b/pkg/services/alerting/notifiers/googlechat.go
index 41f3503640cb5..c00089e0dc57b 100644
--- a/pkg/services/alerting/notifiers/googlechat.go
+++ b/pkg/services/alerting/notifiers/googlechat.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
@@ -29,7 +29,7 @@ func init() {
})
}
-func NewGoogleChatNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewGoogleChatNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -199,7 +199,7 @@ func (this *GoogleChatNotifier) Notify(evalContext *alerting.EvalContext) error
}
body, _ := json.Marshal(res1D)
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.Url,
HttpMethod: "POST",
HttpHeader: headers,
diff --git a/pkg/services/alerting/notifiers/googlechat_test.go b/pkg/services/alerting/notifiers/googlechat_test.go
index 1fdce878926fa..5368eb63c96b1 100644
--- a/pkg/services/alerting/notifiers/googlechat_test.go
+++ b/pkg/services/alerting/notifiers/googlechat_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestGoogleChatNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "googlechat",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestGoogleChatNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "googlechat",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/hipchat_test.go b/pkg/services/alerting/notifiers/hipchat_test.go
index 1597be12eb8b5..57ad03ed7c212 100644
--- a/pkg/services/alerting/notifiers/hipchat_test.go
+++ b/pkg/services/alerting/notifiers/hipchat_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestHipChatNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "hipchat",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestHipChatNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "hipchat",
Settings: settingsJSON,
@@ -59,7 +59,7 @@ func TestHipChatNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "hipchat",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/kafka.go b/pkg/services/alerting/notifiers/kafka.go
index d7da05499b759..168b1646b16b0 100644
--- a/pkg/services/alerting/notifiers/kafka.go
+++ b/pkg/services/alerting/notifiers/kafka.go
@@ -8,7 +8,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -32,7 +32,7 @@ func init() {
})
}
-func NewKafkaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewKafkaNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
endpoint := model.Settings.Get("kafkaRestProxy").MustString()
if endpoint == "" {
return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"}
@@ -101,7 +101,7 @@ func (this *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error {
topicUrl := this.Endpoint + "/topics/" + this.Topic
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: topicUrl,
Body: string(body),
HttpMethod: "POST",
diff --git a/pkg/services/alerting/notifiers/kafka_test.go b/pkg/services/alerting/notifiers/kafka_test.go
index 045976cb14ba5..03a343835e15f 100644
--- a/pkg/services/alerting/notifiers/kafka_test.go
+++ b/pkg/services/alerting/notifiers/kafka_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestKafkaNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "kafka_testing",
Type: "kafka",
Settings: settingsJSON,
@@ -34,7 +34,7 @@ func TestKafkaNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "kafka_testing",
Type: "kafka",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/line.go b/pkg/services/alerting/notifiers/line.go
index edbec373becd5..d8bf70f8b9c93 100644
--- a/pkg/services/alerting/notifiers/line.go
+++ b/pkg/services/alerting/notifiers/line.go
@@ -6,7 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -32,7 +32,7 @@ const (
lineNotifyUrl string = "https://notify-api.line.me/api/notify"
)
-func NewLINENotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewLINENotifier(model *models.AlertNotification) (alerting.Notifier, error) {
token := model.Settings.Get("token").MustString()
if token == "" {
return nil, alerting.ValidationError{Reason: "Could not find token in settings"}
@@ -56,7 +56,7 @@ func (this *LineNotifier) Notify(evalContext *alerting.EvalContext) error {
var err error
switch evalContext.Rule.State {
- case m.AlertStateAlerting:
+ case models.AlertStateAlerting:
err = this.createAlert(evalContext)
}
return err
@@ -79,7 +79,7 @@ func (this *LineNotifier) createAlert(evalContext *alerting.EvalContext) error {
form.Add("imageFullsize", evalContext.ImagePublicUrl)
}
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: lineNotifyUrl,
HttpMethod: "POST",
HttpHeader: map[string]string{
diff --git a/pkg/services/alerting/notifiers/line_test.go b/pkg/services/alerting/notifiers/line_test.go
index 6630665e9924c..69082d0e066e6 100644
--- a/pkg/services/alerting/notifiers/line_test.go
+++ b/pkg/services/alerting/notifiers/line_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -14,7 +14,7 @@ func TestLineNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "line_testing",
Type: "line",
Settings: settingsJSON,
@@ -30,7 +30,7 @@ func TestLineNotifier(t *testing.T) {
"token": "abcdefgh0123456789"
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "line_testing",
Type: "line",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/opsgenie.go b/pkg/services/alerting/notifiers/opsgenie.go
index 84242ea97691d..23dd453fe92e4 100644
--- a/pkg/services/alerting/notifiers/opsgenie.go
+++ b/pkg/services/alerting/notifiers/opsgenie.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -44,7 +44,7 @@ var (
opsgenieAlertURL = "https://api.opsgenie.com/v2/alerts"
)
-func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewOpsGenieNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
autoClose := model.Settings.Get("autoClose").MustBool(true)
apiKey := model.Settings.Get("apiKey").MustString()
apiUrl := model.Settings.Get("apiUrl").MustString()
@@ -76,11 +76,11 @@ func (this *OpsGenieNotifier) Notify(evalContext *alerting.EvalContext) error {
var err error
switch evalContext.Rule.State {
- case m.AlertStateOK:
+ case models.AlertStateOK:
if this.AutoClose {
err = this.closeAlert(evalContext)
}
- case m.AlertStateAlerting:
+ case models.AlertStateAlerting:
err = this.createAlert(evalContext)
}
return err
@@ -115,7 +115,7 @@ func (this *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) err
bodyJSON.Set("details", details)
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.ApiUrl,
Body: string(body),
HttpMethod: "POST",
@@ -139,7 +139,7 @@ func (this *OpsGenieNotifier) closeAlert(evalContext *alerting.EvalContext) erro
bodyJSON.Set("source", "Grafana")
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: fmt.Sprintf("%s/alertId-%d/close?identifierType=alias", this.ApiUrl, evalContext.Rule.Id),
Body: string(body),
HttpMethod: "POST",
diff --git a/pkg/services/alerting/notifiers/opsgenie_test.go b/pkg/services/alerting/notifiers/opsgenie_test.go
index 9dcb9f3c600e5..e4954ed904af6 100644
--- a/pkg/services/alerting/notifiers/opsgenie_test.go
+++ b/pkg/services/alerting/notifiers/opsgenie_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestOpsGenieNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "opsgenie_testing",
Type: "opsgenie",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestOpsGenieNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "opsgenie_testing",
Type: "opsgenie",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/pagerduty.go b/pkg/services/alerting/notifiers/pagerduty.go
index ab2a36fd86b2d..2b60058ecd93f 100644
--- a/pkg/services/alerting/notifiers/pagerduty.go
+++ b/pkg/services/alerting/notifiers/pagerduty.go
@@ -10,7 +10,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -43,7 +43,7 @@ var (
pagerdutyEventApiUrl = "https://events.pagerduty.com/v2/enqueue"
)
-func NewPagerdutyNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewPagerdutyNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
autoResolve := model.Settings.Get("autoResolve").MustBool(false)
key := model.Settings.Get("integrationKey").MustString()
if key == "" {
@@ -67,13 +67,13 @@ type PagerdutyNotifier struct {
func (this *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {
- if evalContext.Rule.State == m.AlertStateOK && !this.AutoResolve {
+ if evalContext.Rule.State == models.AlertStateOK && !this.AutoResolve {
this.log.Info("Not sending a trigger to Pagerduty", "state", evalContext.Rule.State, "auto resolve", this.AutoResolve)
return nil
}
eventType := "trigger"
- if evalContext.Rule.State == m.AlertStateOK {
+ if evalContext.Rule.State == models.AlertStateOK {
eventType = "resolve"
}
customData := triggMetrString
@@ -122,7 +122,7 @@ func (this *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: pagerdutyEventApiUrl,
Body: string(body),
HttpMethod: "POST",
diff --git a/pkg/services/alerting/notifiers/pagerduty_test.go b/pkg/services/alerting/notifiers/pagerduty_test.go
index 1d2eeec4a522e..1698ec7605aca 100644
--- a/pkg/services/alerting/notifiers/pagerduty_test.go
+++ b/pkg/services/alerting/notifiers/pagerduty_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -15,7 +15,7 @@ func TestPagerdutyNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "pageduty_testing",
Type: "pagerduty",
Settings: settingsJSON,
@@ -29,7 +29,7 @@ func TestPagerdutyNotifier(t *testing.T) {
json := `{ "integrationKey": "abcdefgh0123456789" }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "pagerduty_testing",
Type: "pagerduty",
Settings: settingsJSON,
@@ -53,7 +53,7 @@ func TestPagerdutyNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "pagerduty_testing",
Type: "pagerduty",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/pushover.go b/pkg/services/alerting/notifiers/pushover.go
index 0d23bbf6fb3c2..a54fb1ee084da 100644
--- a/pkg/services/alerting/notifiers/pushover.go
+++ b/pkg/services/alerting/notifiers/pushover.go
@@ -10,7 +10,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -95,7 +95,7 @@ func init() {
})
}
-func NewPushoverNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewPushoverNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
userKey := model.Settings.Get("userKey").MustString()
apiToken := model.Settings.Get("apiToken").MustString()
device := model.Settings.Get("device").MustString()
@@ -169,7 +169,7 @@ func (this *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error {
return err
}
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: PUSHOVER_ENDPOINT,
HttpMethod: "POST",
HttpHeader: headers,
@@ -248,7 +248,7 @@ func (this *PushoverNotifier) genPushoverBody(evalContext *alerting.EvalContext,
// Add sound
sound := this.AlertingSound
- if evalContext.Rule.State == m.AlertStateOK {
+ if evalContext.Rule.State == models.AlertStateOK {
sound = this.OkSound
}
if sound != "default" {
diff --git a/pkg/services/alerting/notifiers/pushover_test.go b/pkg/services/alerting/notifiers/pushover_test.go
index 5228491cccd51..f862a500618ae 100644
--- a/pkg/services/alerting/notifiers/pushover_test.go
+++ b/pkg/services/alerting/notifiers/pushover_test.go
@@ -2,12 +2,13 @@ package notifiers
import (
"context"
- "github.com/grafana/grafana/pkg/services/alerting"
"strings"
"testing"
+ "github.com/grafana/grafana/pkg/services/alerting"
+
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -19,7 +20,7 @@ func TestPushoverNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "Pushover",
Type: "pushover",
Settings: settingsJSON,
@@ -40,7 +41,7 @@ func TestPushoverNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "Pushover",
Type: "pushover",
Settings: settingsJSON,
@@ -73,7 +74,7 @@ func TestGenPushoverBody(t *testing.T) {
Convey("When alert is firing - should use siren sound", func() {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
- State: m.AlertStateAlerting,
+ State: models.AlertStateAlerting,
})
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
@@ -84,7 +85,7 @@ func TestGenPushoverBody(t *testing.T) {
Convey("When alert is ok - should use success sound", func() {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
- State: m.AlertStateOK,
+ State: models.AlertStateOK,
})
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
diff --git a/pkg/services/alerting/notifiers/sensu.go b/pkg/services/alerting/notifiers/sensu.go
index b018c53208e8f..cad9fc2286a3b 100644
--- a/pkg/services/alerting/notifiers/sensu.go
+++ b/pkg/services/alerting/notifiers/sensu.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -44,7 +44,7 @@ func init() {
}
-func NewSensuNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewSensuNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -117,7 +117,7 @@ func (this *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.Url,
User: this.User,
Password: this.Password,
diff --git a/pkg/services/alerting/notifiers/sensu_test.go b/pkg/services/alerting/notifiers/sensu_test.go
index 40e3b1e1cc310..40d39a5d1c3f9 100644
--- a/pkg/services/alerting/notifiers/sensu_test.go
+++ b/pkg/services/alerting/notifiers/sensu_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestSensuNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "sensu",
Type: "sensu",
Settings: settingsJSON,
@@ -35,7 +35,7 @@ func TestSensuNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "sensu",
Type: "sensu",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go
index 7754b7de71aa3..1176744488778 100644
--- a/pkg/services/alerting/notifiers/slack.go
+++ b/pkg/services/alerting/notifiers/slack.go
@@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
@@ -99,7 +99,7 @@ func init() {
}
-func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewSlackNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -171,7 +171,7 @@ func (this *SlackNotifier) Notify(evalContext *alerting.EvalContext) error {
}
message := this.Mention
- if evalContext.Rule.State != m.AlertStateOK { //don't add message when going back to alert state ok.
+ if evalContext.Rule.State != models.AlertStateOK { //don't add message when going back to alert state ok.
message += " " + evalContext.Rule.Message
}
image_url := ""
@@ -212,7 +212,7 @@ func (this *SlackNotifier) Notify(evalContext *alerting.EvalContext) error {
body["icon_url"] = this.IconUrl
}
data, _ := json.Marshal(&body)
- cmd := &m.SendWebhookSync{Url: this.Url, Body: string(data)}
+ cmd := &models.SendWebhookSync{Url: this.Url, Body: string(data)}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
this.log.Error("Failed to send slack notification", "error", err, "webhook", this.Name)
return err
@@ -235,7 +235,7 @@ func SlackFileUpload(evalContext *alerting.EvalContext, log log.Logger, url stri
if err != nil {
return err
}
- cmd := &m.SendWebhookSync{Url: url, Body: uploadBody.String(), HttpHeader: headers, HttpMethod: "POST"}
+ cmd := &models.SendWebhookSync{Url: url, Body: uploadBody.String(), HttpHeader: headers, HttpMethod: "POST"}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
log.Error("Failed to upload slack image", "error", err, "webhook", "file.upload")
return err
diff --git a/pkg/services/alerting/notifiers/slack_test.go b/pkg/services/alerting/notifiers/slack_test.go
index 17362bc850b6a..7dceb12676c9d 100644
--- a/pkg/services/alerting/notifiers/slack_test.go
+++ b/pkg/services/alerting/notifiers/slack_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestSlackNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "slack",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestSlackNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "slack",
Settings: settingsJSON,
@@ -67,7 +67,7 @@ func TestSlackNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "slack",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go
index e33a93f8a0cfa..57f5d6e91c04a 100644
--- a/pkg/services/alerting/notifiers/teams.go
+++ b/pkg/services/alerting/notifiers/teams.go
@@ -5,7 +5,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -26,7 +26,7 @@ func init() {
}
-func NewTeamsNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewTeamsNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -74,7 +74,7 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
}
message := ""
- if evalContext.Rule.State != m.AlertStateOK { //don't add message when going back to alert state ok.
+ if evalContext.Rule.State != models.AlertStateOK { //don't add message when going back to alert state ok.
message = evalContext.Rule.Message
}
@@ -126,7 +126,7 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
}
data, _ := json.Marshal(&body)
- cmd := &m.SendWebhookSync{Url: this.Url, Body: string(data)}
+ cmd := &models.SendWebhookSync{Url: this.Url, Body: string(data)}
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
this.log.Error("Failed to send teams notification", "error", err, "webhook", this.Name)
diff --git a/pkg/services/alerting/notifiers/teams_test.go b/pkg/services/alerting/notifiers/teams_test.go
index a964735073635..1dd35c899605c 100644
--- a/pkg/services/alerting/notifiers/teams_test.go
+++ b/pkg/services/alerting/notifiers/teams_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestTeamsNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "teams",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestTeamsNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "teams",
Settings: settingsJSON,
@@ -55,7 +55,7 @@ func TestTeamsNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "teams",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go
index a5876b77b2283..741c0fe732c5c 100644
--- a/pkg/services/alerting/notifiers/telegram.go
+++ b/pkg/services/alerting/notifiers/telegram.go
@@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -60,7 +60,7 @@ type TelegramNotifier struct {
log log.Logger
}
-func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewTelegramNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
@@ -86,7 +86,7 @@ func NewTelegramNotifier(model *m.AlertNotification) (alerting.Notifier, error)
}, nil
}
-func (this *TelegramNotifier) buildMessage(evalContext *alerting.EvalContext, sendImageInline bool) *m.SendWebhookSync {
+func (this *TelegramNotifier) buildMessage(evalContext *alerting.EvalContext, sendImageInline bool) *models.SendWebhookSync {
if sendImageInline {
cmd, err := this.buildMessageInlineImage(evalContext)
if err == nil {
@@ -98,7 +98,7 @@ func (this *TelegramNotifier) buildMessage(evalContext *alerting.EvalContext, se
return this.buildMessageLinkedImage(evalContext)
}
-func (this *TelegramNotifier) buildMessageLinkedImage(evalContext *alerting.EvalContext) *m.SendWebhookSync {
+func (this *TelegramNotifier) buildMessageLinkedImage(evalContext *alerting.EvalContext) *models.SendWebhookSync {
message := fmt.Sprintf("%s\nState: %s\nMessage: %s\n", evalContext.GetNotificationTitle(), evalContext.Rule.Name, evalContext.Rule.Message)
ruleUrl, err := evalContext.GetRuleUrl()
@@ -122,7 +122,7 @@ func (this *TelegramNotifier) buildMessageLinkedImage(evalContext *alerting.Eval
return cmd
}
-func (this *TelegramNotifier) buildMessageInlineImage(evalContext *alerting.EvalContext) (*m.SendWebhookSync, error) {
+func (this *TelegramNotifier) buildMessageInlineImage(evalContext *alerting.EvalContext) (*models.SendWebhookSync, error) {
var imageFile *os.File
var err error
@@ -153,7 +153,7 @@ func (this *TelegramNotifier) buildMessageInlineImage(evalContext *alerting.Eval
return cmd, nil
}
-func (this *TelegramNotifier) generateTelegramCmd(message string, messageField string, apiAction string, extraConf func(writer *multipart.Writer)) *m.SendWebhookSync {
+func (this *TelegramNotifier) generateTelegramCmd(message string, messageField string, apiAction string, extraConf func(writer *multipart.Writer)) *models.SendWebhookSync {
var body bytes.Buffer
w := multipart.NewWriter(&body)
@@ -170,7 +170,7 @@ func (this *TelegramNotifier) generateTelegramCmd(message string, messageField s
this.log.Info("Sending telegram notification", "chat_id", this.ChatID, "bot_token", this.BotToken, "apiAction", apiAction)
url := fmt.Sprintf(telegramApiUrl, this.BotToken, apiAction)
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: url,
Body: body.String(),
HttpMethod: "POST",
@@ -227,7 +227,7 @@ func appendIfPossible(message string, extra string, sizeLimit int) string {
}
func (this *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error {
- var cmd *m.SendWebhookSync
+ var cmd *models.SendWebhookSync
if evalContext.ImagePublicUrl == "" && this.UploadImage {
cmd = this.buildMessage(evalContext, true)
} else {
diff --git a/pkg/services/alerting/notifiers/telegram_test.go b/pkg/services/alerting/notifiers/telegram_test.go
index 9906a2ffd9575..3559555439e57 100644
--- a/pkg/services/alerting/notifiers/telegram_test.go
+++ b/pkg/services/alerting/notifiers/telegram_test.go
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
. "github.com/smartystreets/goconvey/convey"
)
@@ -18,7 +18,7 @@ func TestTelegramNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "telegram_testing",
Type: "telegram",
Settings: settingsJSON,
@@ -36,7 +36,7 @@ func TestTelegramNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "telegram_testing",
Type: "telegram",
Settings: settingsJSON,
@@ -57,7 +57,7 @@ func TestTelegramNotifier(t *testing.T) {
&alerting.Rule{
Name: "This is an alarm",
Message: "Some kind of message.",
- State: m.AlertStateOK,
+ State: models.AlertStateOK,
})
caption := generateImageCaption(evalContext, "http://grafa.url/abcdef", "")
@@ -74,7 +74,7 @@ func TestTelegramNotifier(t *testing.T) {
&alerting.Rule{
Name: "This is an alarm",
Message: "Some kind of message.",
- State: m.AlertStateOK,
+ State: models.AlertStateOK,
})
caption := generateImageCaption(evalContext,
@@ -92,7 +92,7 @@ func TestTelegramNotifier(t *testing.T) {
&alerting.Rule{
Name: "This is an alarm",
Message: "Some kind of message that is too long for appending to our pretty little message, this line is actually exactly 197 chars long and I will get there in the end I promise I will. Yes siree that's it. But suddenly Telegram increased the length so now we need some lorem ipsum to fix this test. Here we go: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur molestie cursus. Donec suscipit egestas nisi. Proin ut efficitur ex. Mauris mi augue, volutpat a nisi vel, euismod dictum arcu. Sed quis tempor eros, sed malesuada dolor. Ut orci augue, viverra sit amet blandit quis, faucibus sit amet ex. Duis condimentum efficitur lectus, id dignissim quam tempor id. Morbi sollicitudin rhoncus diam, id tincidunt lectus scelerisque vitae. Etiam imperdiet semper sem, vel eleifend ligula mollis eget. Etiam ultrices fringilla lacus, sit amet pharetra ex blandit quis. Suspendisse in egestas neque, et posuere lectus. Vestibulum eu ex dui. Sed molestie nulla a lobortis scelerisque. Nulla ipsum ex, iaculis vitae vehicula sit amet, fermentum eu eros.",
- State: m.AlertStateOK,
+ State: models.AlertStateOK,
})
caption := generateImageCaption(evalContext,
@@ -109,7 +109,7 @@ func TestTelegramNotifier(t *testing.T) {
&alerting.Rule{
Name: "This is an alarm",
Message: "Some kind of message that is too long for appending to our pretty little message, this line is actually exactly 197 chars long and I will get there in the end I promise I will. Yes siree that's it. But suddenly Telegram increased the length so now we need some lorem ipsum to fix this test. Here we go: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur molestie cursus. Donec suscipit egestas nisi. Proin ut efficitur ex. Mauris mi augue, volutpat a nisi vel, euismod dictum arcu. Sed quis tempor eros, sed malesuada dolor. Ut orci augue, viverra sit amet blandit quis, faucibus sit amet ex. Duis condimentum efficitur lectus, id dignissim quam tempor id. Morbi sollicitudin rhoncus diam, id tincidunt lectus scelerisque vitae. Etiam imperdiet semper sem, vel eleifend ligula mollis eget. Etiam ultrices fringilla lacus, sit amet pharetra ex blandit quis. Suspendisse in egestas neque, et posuere lectus. Vestibulum eu ex dui. Sed molestie nulla a lobortis sceleri",
- State: m.AlertStateOK,
+ State: models.AlertStateOK,
})
caption := generateImageCaption(evalContext,
diff --git a/pkg/services/alerting/notifiers/threema.go b/pkg/services/alerting/notifiers/threema.go
index 2360073d22814..6e4aa7bc946ee 100644
--- a/pkg/services/alerting/notifiers/threema.go
+++ b/pkg/services/alerting/notifiers/threema.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -76,7 +76,7 @@ type ThreemaNotifier struct {
log log.Logger
}
-func NewThreemaNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewThreemaNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
@@ -127,11 +127,11 @@ func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error
// Determine emoji
stateEmoji := ""
switch evalContext.Rule.State {
- case m.AlertStateOK:
+ case models.AlertStateOK:
stateEmoji = "\u2705 " // White Heavy Check Mark
- case m.AlertStateNoData:
+ case models.AlertStateNoData:
stateEmoji = "\u2753 " // Black Question Mark Ornament
- case m.AlertStateAlerting:
+ case models.AlertStateAlerting:
stateEmoji = "\u26A0 " // Warning sign
}
@@ -154,7 +154,7 @@ func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error
headers := map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
}
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: url,
Body: body,
HttpMethod: "POST",
diff --git a/pkg/services/alerting/notifiers/threema_test.go b/pkg/services/alerting/notifiers/threema_test.go
index 3f23730a249a0..2c50b7d2058ca 100644
--- a/pkg/services/alerting/notifiers/threema_test.go
+++ b/pkg/services/alerting/notifiers/threema_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
. "github.com/smartystreets/goconvey/convey"
)
@@ -17,7 +17,7 @@ func TestThreemaNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "threema_testing",
Type: "threema",
Settings: settingsJSON,
@@ -36,7 +36,7 @@ func TestThreemaNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "threema_testing",
Type: "threema",
Settings: settingsJSON,
@@ -63,7 +63,7 @@ func TestThreemaNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "threema_testing",
Type: "threema",
Settings: settingsJSON,
@@ -83,7 +83,7 @@ func TestThreemaNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "threema_testing",
Type: "threema",
Settings: settingsJSON,
@@ -103,7 +103,7 @@ func TestThreemaNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "threema_testing",
Type: "threema",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/victorops_test.go b/pkg/services/alerting/notifiers/victorops_test.go
index 6ac806a82cc57..258d2900a22ba 100644
--- a/pkg/services/alerting/notifiers/victorops_test.go
+++ b/pkg/services/alerting/notifiers/victorops_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestVictoropsNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "victorops_testing",
Type: "victorops",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestVictoropsNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "victorops_testing",
Type: "victorops",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go
index 7c582a41aeb86..31b5f7a820803 100644
--- a/pkg/services/alerting/notifiers/webhook.go
+++ b/pkg/services/alerting/notifiers/webhook.go
@@ -4,7 +4,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
@@ -40,7 +40,7 @@ func init() {
}
-func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
+func NewWebHookNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -90,7 +90,7 @@ func (this *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error {
body, _ := bodyJSON.MarshalJSON()
- cmd := &m.SendWebhookSync{
+ cmd := &models.SendWebhookSync{
Url: this.Url,
User: this.User,
Password: this.Password,
diff --git a/pkg/services/alerting/notifiers/webhook_test.go b/pkg/services/alerting/notifiers/webhook_test.go
index b2d944eb6e944..af48f1f1aa6dd 100644
--- a/pkg/services/alerting/notifiers/webhook_test.go
+++ b/pkg/services/alerting/notifiers/webhook_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,7 +16,7 @@ func TestWebhookNotifier(t *testing.T) {
json := `{ }`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "webhook",
Settings: settingsJSON,
@@ -33,7 +33,7 @@ func TestWebhookNotifier(t *testing.T) {
}`
settingsJSON, _ := simplejson.NewJson([]byte(json))
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: "ops",
Type: "webhook",
Settings: settingsJSON,
diff --git a/pkg/services/alerting/reader.go b/pkg/services/alerting/reader.go
index 3f033a746f273..0df826e9ea5d7 100644
--- a/pkg/services/alerting/reader.go
+++ b/pkg/services/alerting/reader.go
@@ -7,7 +7,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
type RuleReader interface {
@@ -16,7 +16,6 @@ type RuleReader interface {
type DefaultRuleReader struct {
sync.RWMutex
- //serverID string
serverPosition int
clusterSize int
log log.Logger
@@ -40,7 +39,7 @@ func (arr *DefaultRuleReader) initReader() {
}
func (arr *DefaultRuleReader) Fetch() []*Rule {
- cmd := &m.GetAllAlertsQuery{}
+ cmd := &models.GetAllAlertsQuery{}
if err := bus.Dispatch(cmd); err != nil {
arr.log.Error("Could not load alerts", "error", err)
diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go
index 6f2669ff41a99..d82421d7506d5 100644
--- a/pkg/services/alerting/result_handler.go
+++ b/pkg/services/alerting/result_handler.go
@@ -7,7 +7,8 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
+
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/rendering"
)
@@ -47,7 +48,7 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
if evalContext.ShouldUpdateAlertState() {
handler.log.Info("New state change", "alertId", evalContext.Rule.Id, "newState", evalContext.Rule.State, "prev state", evalContext.PrevAlertState)
- cmd := &m.SetAlertStateCommand{
+ cmd := &models.SetAlertStateCommand{
AlertId: evalContext.Rule.Id,
OrgId: evalContext.Rule.OrgId,
State: evalContext.Rule.State,
@@ -56,12 +57,12 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error {
}
if err := bus.Dispatch(cmd); err != nil {
- if err == m.ErrCannotChangeStateOnPausedAlert {
+ if err == models.ErrCannotChangeStateOnPausedAlert {
handler.log.Error("Cannot change state on alert that's paused", "error", err)
return err
}
- if err == m.ErrRequiresNewState {
+ if err == models.ErrRequiresNewState {
handler.log.Info("Alert already updated")
return nil
}
diff --git a/pkg/services/alerting/rule.go b/pkg/services/alerting/rule.go
index f62690a2d9606..b5b6f4660e64e 100644
--- a/pkg/services/alerting/rule.go
+++ b/pkg/services/alerting/rule.go
@@ -8,7 +8,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
var (
@@ -26,9 +26,9 @@ type Rule struct {
Message string
LastStateChange time.Time
For time.Duration
- NoDataState m.NoDataOption
- ExecutionErrorState m.ExecutionErrorOption
- State m.AlertStateType
+ NoDataState models.NoDataOption
+ ExecutionErrorState models.ExecutionErrorOption
+ State models.AlertStateType
Conditions []Condition
Notifications []string
@@ -103,7 +103,7 @@ func getTimeDurationStringToSeconds(str string) (int64, error) {
return int64(value * multiplier), nil
}
-func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) {
+func NewRuleFromDBAlert(ruleDef *models.Alert) (*Rule, error) {
model := &Rule{}
model.Id = ruleDef.Id
model.OrgId = ruleDef.OrgId
@@ -114,8 +114,8 @@ func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) {
model.State = ruleDef.State
model.LastStateChange = ruleDef.NewStateDate
model.For = ruleDef.For
- model.NoDataState = m.NoDataOption(ruleDef.Settings.Get("noDataState").MustString("no_data"))
- model.ExecutionErrorState = m.ExecutionErrorOption(ruleDef.Settings.Get("executionErrorState").MustString("alerting"))
+ model.NoDataState = models.NoDataOption(ruleDef.Settings.Get("noDataState").MustString("no_data"))
+ model.ExecutionErrorState = models.ExecutionErrorOption(ruleDef.Settings.Get("executionErrorState").MustString("alerting"))
model.StateChanges = ruleDef.StateChanges
model.Frequency = ruleDef.Frequency
diff --git a/pkg/services/alerting/rule_test.go b/pkg/services/alerting/rule_test.go
index ca533c36210f1..853fb5d17b5cf 100644
--- a/pkg/services/alerting/rule_test.go
+++ b/pkg/services/alerting/rule_test.go
@@ -4,7 +4,7 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
)
@@ -60,10 +60,10 @@ func TestAlertRuleModel(t *testing.T) {
})
Convey("can construct alert rule model", func() {
- firstNotification := m.CreateAlertNotificationCommand{OrgId: 1, Name: "1"}
+ firstNotification := models.CreateAlertNotificationCommand{OrgId: 1, Name: "1"}
err := sqlstore.CreateAlertNotificationCommand(&firstNotification)
So(err, ShouldBeNil)
- secondNotification := m.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
+ secondNotification := models.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
err = sqlstore.CreateAlertNotificationCommand(&secondNotification)
So(err, ShouldBeNil)
@@ -92,7 +92,7 @@ func TestAlertRuleModel(t *testing.T) {
alertJSON, jsonErr := simplejson.NewJson([]byte(json))
So(jsonErr, ShouldBeNil)
- alert := &m.Alert{
+ alert := &models.Alert{
Id: 1,
OrgId: 1,
DashboardId: 1,
@@ -129,7 +129,7 @@ func TestAlertRuleModel(t *testing.T) {
alertJSON, jsonErr := simplejson.NewJson([]byte(json))
So(jsonErr, ShouldBeNil)
- alert := &m.Alert{
+ alert := &models.Alert{
Id: 1,
OrgId: 1,
DashboardId: 1,
@@ -167,7 +167,7 @@ func TestAlertRuleModel(t *testing.T) {
alertJSON, jsonErr := simplejson.NewJson([]byte(json))
So(jsonErr, ShouldBeNil)
- alert := &m.Alert{
+ alert := &models.Alert{
Id: 1,
OrgId: 1,
DashboardId: 1,
diff --git a/pkg/services/alerting/test_notification.go b/pkg/services/alerting/test_notification.go
index fbb1633d4a5b0..5cb18d2b42ee1 100644
--- a/pkg/services/alerting/test_notification.go
+++ b/pkg/services/alerting/test_notification.go
@@ -8,11 +8,11 @@ import (
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
type NotificationTestCommand struct {
- State m.AlertStateType
+ State models.AlertStateType
Name string
Type string
Settings *simplejson.Json
@@ -29,7 +29,7 @@ func init() {
func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
notifier := NewNotificationService(nil).(*notificationService)
- model := &m.AlertNotification{
+ model := &models.AlertNotification{
Name: cmd.Name,
Type: cmd.Type,
Settings: cmd.Settings,
@@ -51,7 +51,7 @@ func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext {
PanelId: 1,
Name: "Test notification",
Message: "Someone is testing the alert notification within grafana.",
- State: m.AlertStateAlerting,
+ State: models.AlertStateAlerting,
}
ctx := NewEvalContext(context.Background(), testRule)
diff --git a/pkg/services/alerting/test_rule.go b/pkg/services/alerting/test_rule.go
index 360ee065de0f5..736dd287dbecb 100644
--- a/pkg/services/alerting/test_rule.go
+++ b/pkg/services/alerting/test_rule.go
@@ -6,14 +6,14 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
)
type AlertTestCommand struct {
Dashboard *simplejson.Json
PanelId int64
OrgId int64
- User *m.SignedInUser
+ User *models.SignedInUser
Result *EvalContext
}
@@ -24,7 +24,7 @@ func init() {
func handleAlertTestCommand(cmd *AlertTestCommand) error {
- dash := m.NewDashboardFromJson(cmd.Dashboard)
+ dash := models.NewDashboardFromJson(cmd.Dashboard)
extractor := NewDashAlertExtractor(dash, cmd.OrgId, cmd.User)
alerts, err := extractor.GetAlerts()
diff --git a/pkg/services/ldap/settings.go b/pkg/services/ldap/settings.go
index de2da2402bfef..0a0f66d9d7347 100644
--- a/pkg/services/ldap/settings.go
+++ b/pkg/services/ldap/settings.go
@@ -5,12 +5,12 @@ import (
"sync"
"github.com/BurntSushi/toml"
- "github.com/grafana/grafana/pkg/util/errutil"
"golang.org/x/xerrors"
"github.com/grafana/grafana/pkg/infra/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
+ "github.com/grafana/grafana/pkg/util/errutil"
)
type Config struct {
@@ -68,9 +68,10 @@ func IsEnabled() bool {
// ReloadConfig reads the config from the disc and caches it.
func ReloadConfig() error {
- if IsEnabled() == false {
+ if !IsEnabled() {
return nil
}
+
loadingMutex.Lock()
defer loadingMutex.Unlock()
@@ -82,7 +83,7 @@ func ReloadConfig() error {
// GetConfig returns the LDAP config if LDAP is enabled otherwise it returns nil. It returns either cached value of
// the config or it reads it and caches it first.
func GetConfig() (*Config, error) {
- if IsEnabled() == false {
+ if !IsEnabled() {
return nil, nil
}
diff --git a/public/app/core/components/info_popover.ts b/public/app/core/components/info_popover.ts
index 9c5694188d6ea..7045146593033 100644
--- a/public/app/core/components/info_popover.ts
+++ b/public/app/core/components/info_popover.ts
@@ -8,7 +8,7 @@ export function infoPopover() {
restrict: 'E',
template: '',
transclude: true,
- link: (scope: any, elem: any, attrs: any, transclude: any) => {
+ link: (scope: any, elem: any, attrs: any, ctrl: any, transclude: any) => {
const offset = attrs.offset || '0 -10px';
const position = attrs.position || 'right middle';
let classes = 'drop-help drop-hide-out-of-bounds';
diff --git a/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap b/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
index 23d4d714559d3..bb1ba9c9388f8 100644
--- a/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
+++ b/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
@@ -212,7 +212,7 @@ exports[`ServerStats Should render table with stats 1`] = `
{
showLoadingState: false,
fullscreenPanel: null,
scrollTop: 0,
+ updateScrollTop: null,
rememberScrollTop: 0,
};
@@ -168,7 +170,7 @@ export class DashboardPage extends PureComponent
{
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 {
setScrollTop = (e: MouseEvent): 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 {
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 {
/>
diff --git a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap
index 20fc00cafc01f..d6be7658841bb 100644
--- a/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap
+++ b/public/app/features/dashboard/containers/__snapshots__/DashboardPage.test.tsx.snap
@@ -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}
>
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
new file mode 100644
index 0000000000000..28845d4f463e0
--- /dev/null
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
@@ -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;
+ setup?: (fn: () => void) => void;
+ setProps: (props: Partial) => 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) => {
+ Object.assign(ctx.props, props);
+ if (ctx.wrapper) {
+ ctx.wrapper.setProps(ctx.props);
+ }
+ },
+ };
+
+ beforeEach(() => {
+ setupFn();
+ ctx.wrapper = shallow();
+ });
+
+ scenarioFn(ctx);
+ });
+}
+
+describe('DashboardGrid', () => {
+ dashboardGridScenario('Can render dashboard grid', ctx => {
+ ctx.setup(() => {});
+
+ it('Should render', () => {
+ expect(ctx.wrapper).toMatchSnapshot();
+ });
+ });
+});
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
index 5651b99f4cfdd..6f57f6f42e391 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
@@ -205,7 +205,7 @@ export class DashboardGrid extends PureComponent {
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;
diff --git a/public/app/features/dashboard/dashgrid/DashboardGridDirective.ts b/public/app/features/dashboard/dashgrid/DashboardGridDirective.ts
deleted file mode 100644
index bb81c936b3ea0..0000000000000
--- a/public/app/features/dashboard/dashgrid/DashboardGridDirective.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { react2AngularDirective } from 'app/core/utils/react2angular';
-import DashboardGrid from './DashboardGrid';
-
-react2AngularDirective('dashboardGrid', DashboardGrid, [['dashboard', { watchDepth: 'reference' }]]);
diff --git a/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap
new file mode 100644
index 0000000000000..38172a3044f5d
--- /dev/null
+++ b/public/app/features/dashboard/dashgrid/__snapshots__/DashboardGrid.test.tsx.snap
@@ -0,0 +1,996 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/public/app/features/dashboard/index.ts b/public/app/features/dashboard/index.ts
index 5e31a49f40f8a..1a326d73bd9e9 100644
--- a/public/app/features/dashboard/index.ts
+++ b/public/app/features/dashboard/index.ts
@@ -1,5 +1,3 @@
-import './dashgrid/DashboardGridDirective';
-
// Services
import './services/UnsavedChangesSrv';
import './services/DashboardLoaderSrv';
diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
index 575311c2d1746..6f9939e882b9d 100644
--- a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
+++ b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
@@ -19,7 +19,7 @@ const setup = (propOverrides?: object) => {
setDataSourceName,
updateDataSource: jest.fn(),
setIsDefault,
- plugin: pluginMock,
+ query: {},
...propOverrides,
};
@@ -45,7 +45,6 @@ describe('Render', () => {
it('should render beta info text', () => {
const wrapper = setup({
dataSourceMeta: { ...getMockPlugin(), state: 'beta' },
- plugin: pluginMock,
});
expect(wrapper).toMatchSnapshot();
diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
index e02684d57fcc5..5c31b946149c0 100644
--- a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
+++ b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
@@ -2,6 +2,7 @@
import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
+import isString from 'lodash/isString';
// Components
import Page from 'app/core/components/Page/Page';
@@ -21,7 +22,7 @@ import { getNavModel } from 'app/core/selectors/navModel';
import { getRouteParamsId } from 'app/core/selectors/location';
// Types
-import { StoreState } from 'app/types/';
+import { StoreState, UrlQueryMap } from 'app/types/';
import { NavModel, DataSourceSettings, DataSourcePluginMeta } from '@grafana/ui';
import { getDataSourceLoadingNav } from '../state/navModel';
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
@@ -38,14 +39,17 @@ export interface Props {
updateDataSource: typeof updateDataSource;
setIsDefault: typeof setIsDefault;
plugin?: GenericDataSourcePlugin;
+ query: UrlQueryMap;
+ page?: string;
}
interface State {
dataSource: DataSourceSettings;
- plugin: GenericDataSourcePlugin;
+ plugin?: GenericDataSourcePlugin;
isTesting?: boolean;
testingMessage?: string;
testingStatus?: string;
+ loadError?: any;
}
export class DataSourceSettingsPage extends PureComponent {
@@ -73,9 +77,17 @@ export class DataSourceSettingsPage extends PureComponent {
async componentDidMount() {
const { loadDataSource, pageId } = this.props;
- await loadDataSource(pageId);
- if (!this.state.plugin) {
- await this.loadPlugin();
+ if (isNaN(pageId)) {
+ this.setState({ loadError: 'Invalid ID' });
+ return;
+ }
+ try {
+ await loadDataSource(pageId);
+ if (!this.state.plugin) {
+ await this.loadPlugin();
+ }
+ } catch (err) {
+ this.setState({ loadError: err });
}
}
@@ -174,70 +186,133 @@ export class DataSourceSettingsPage extends PureComponent {
return this.state.dataSource.id > 0;
}
- render() {
- const { dataSourceMeta, navModel, setDataSourceName, setIsDefault } = this.props;
- const { testingMessage, testingStatus, plugin, dataSource } = this.state;
+ renderLoadError(loadError: any) {
+ let showDelete = false;
+ let msg = loadError.toString();
+ if (loadError.data) {
+ if (loadError.data.message) {
+ msg = loadError.data.message;
+ }
+ } else if (isString(loadError)) {
+ showDelete = true;
+ }
+
+ const node = {
+ text: msg,
+ subTitle: 'Data Source Error',
+ icon: 'fa fa-fw fa-warning',
+ };
+ const nav = {
+ node: node,
+ main: node,
+ };
return (
-
-
- {this.hasDataSource && (
-
-
+ return (
+
+ );
+ }
+
+ render() {
+ const { navModel, page } = this.props;
+ const { loadError } = this.state;
+
+ if (loadError) {
+ return this.renderLoadError(loadError);
+ }
+
+ return (
+
+
+ {this.hasDataSource && {page ? this.renderConfigPageBody(page) : this.renderSettings()}
}
);
@@ -247,11 +322,19 @@ export class DataSourceSettingsPage extends PureComponent
{
function mapStateToProps(state: StoreState) {
const pageId = getRouteParamsId(state.location);
const dataSource = getDataSource(state.dataSources, pageId);
+ const page = state.location.query.page as string;
+
return {
- navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`, getDataSourceLoadingNav('settings')),
+ navModel: getNavModel(
+ state.navIndex,
+ page ? `datasource-page-${page}` : `datasource-settings-${pageId}`,
+ getDataSourceLoadingNav('settings')
+ ),
dataSource: getDataSource(state.dataSources, pageId),
dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type),
pageId: pageId,
+ query: state.location.query,
+ page,
};
}
diff --git a/public/app/features/datasources/settings/PluginSettings.tsx b/public/app/features/datasources/settings/PluginSettings.tsx
index 94c054d56ee94..a7462cbb45c72 100644
--- a/public/app/features/datasources/settings/PluginSettings.tsx
+++ b/public/app/features/datasources/settings/PluginSettings.tsx
@@ -54,7 +54,7 @@ export class PluginSettings extends PureComponent {
}
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps: Props) {
const { plugin } = this.props;
if (!plugin.components.ConfigEditor && this.props.dataSource !== prevProps.dataSource) {
this.scopeProps.ctrl.current = _.cloneDeep(this.props.dataSource);
diff --git a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap
index 2ca6a2ee28f03..063ebf8418ded 100644
--- a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap
+++ b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap
@@ -153,78 +153,6 @@ exports[`Render should render beta info text 1`] = `
onDefaultChange={[Function]}
onNameChange={[Function]}
/>
-
@@ -257,77 +185,6 @@ exports[`Render should render component 1`] = `
onDefaultChange={[Function]}
onNameChange={[Function]}
/>
-
diff --git a/public/app/features/datasources/state/actions.ts b/public/app/features/datasources/state/actions.ts
index 80ec72e6376f1..9fb003bc0c4c1 100644
--- a/public/app/features/datasources/state/actions.ts
+++ b/public/app/features/datasources/state/actions.ts
@@ -10,6 +10,7 @@ import { StoreState, LocationUpdate } from 'app/types';
import { actionCreatorFactory } from 'app/core/redux';
import { ActionOf, noPayloadActionCreatorFactory } from 'app/core/redux/actionCreatorFactory';
import { getPluginSettings } from 'app/features/plugins/PluginSettingsCache';
+import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader';
export const dataSourceLoaded = actionCreatorFactory('LOAD_DATA_SOURCE').create();
@@ -52,9 +53,11 @@ export function loadDataSource(id: number): ThunkResult {
return async dispatch => {
const dataSource = await getBackendSrv().get(`/api/datasources/${id}`);
const pluginInfo = (await getPluginSettings(dataSource.type)) as DataSourcePluginMeta;
+ const plugin = await importDataSourcePlugin(pluginInfo);
+
dispatch(dataSourceLoaded(dataSource));
dispatch(dataSourceMetaLoaded(pluginInfo));
- dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo)));
+ dispatch(updateNavIndex(buildNavModel(dataSource, plugin)));
};
}
diff --git a/public/app/features/datasources/state/navModel.ts b/public/app/features/datasources/state/navModel.ts
index 6fdc6f5762f80..6b5f679451de4 100644
--- a/public/app/features/datasources/state/navModel.ts
+++ b/public/app/features/datasources/state/navModel.ts
@@ -1,7 +1,10 @@
-import { PluginMeta, DataSourceSettings, PluginType, NavModel, NavModelItem, PluginInclude } from '@grafana/ui';
+import { DataSourceSettings, PluginType, NavModel, NavModelItem, PluginInclude } from '@grafana/ui';
import config from 'app/core/config';
+import { GenericDataSourcePlugin } from '../settings/PluginSettings';
+
+export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDataSourcePlugin): NavModelItem {
+ const pluginMeta = plugin.meta;
-export function buildNavModel(dataSource: DataSourceSettings, pluginMeta: PluginMeta): NavModelItem {
const navModel = {
img: pluginMeta.info.logos.large,
id: 'datasource-' + dataSource.id,
@@ -20,6 +23,18 @@ export function buildNavModel(dataSource: DataSourceSettings, pluginMeta: Plugin
],
};
+ if (plugin.configPages) {
+ for (const page of plugin.configPages) {
+ navModel.children.push({
+ active: false,
+ text: page.title,
+ icon: page.icon,
+ url: `datasources/edit/${dataSource.id}/?page=${page.id}`,
+ id: `datasource-page-${page.id}`,
+ });
+ }
+ }
+
if (pluginMeta.includes && hasDashboards(pluginMeta.includes)) {
navModel.children.push({
active: false,
@@ -65,28 +80,30 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
user: '',
},
{
- id: '1',
- type: PluginType.datasource,
- name: '',
- info: {
- author: {
- name: '',
- url: '',
- },
- description: '',
- links: [{ name: '', url: '' }],
- logos: {
- large: '',
- small: '',
+ meta: {
+ id: '1',
+ type: PluginType.datasource,
+ name: '',
+ info: {
+ author: {
+ name: '',
+ url: '',
+ },
+ description: '',
+ links: [{ name: '', url: '' }],
+ logos: {
+ large: '',
+ small: '',
+ },
+ screenshots: [],
+ updated: '',
+ version: '',
},
- screenshots: [],
- updated: '',
- version: '',
+ includes: [],
+ module: '',
+ baseUrl: '',
},
- includes: [],
- module: '',
- baseUrl: '',
- }
+ } as GenericDataSourcePlugin
);
let node: NavModelItem;
diff --git a/public/app/features/explore/Graph.tsx b/public/app/features/explore/Graph.tsx
index f9c48fc92c722..b5cdca318afa6 100644
--- a/public/app/features/explore/Graph.tsx
+++ b/public/app/features/explore/Graph.tsx
@@ -1,17 +1,15 @@
import $ from 'jquery';
import React, { PureComponent } from 'react';
+import difference from 'lodash/difference';
import 'vendor/flot/jquery.flot';
import 'vendor/flot/jquery.flot.time';
import 'vendor/flot/jquery.flot.selection';
import 'vendor/flot/jquery.flot.stack';
-import { TimeZone, AbsoluteTimeRange } from '@grafana/ui';
+import { TimeZone, AbsoluteTimeRange, GraphLegend, LegendItem, LegendDisplayMode } from '@grafana/ui';
import TimeSeries from 'app/core/time_series2';
-import Legend from './Legend';
-import { equal, intersect } from './utils/set';
-
const MAX_NUMBER_OF_TIME_SERIES = 20;
// Copied from graph.ts
@@ -89,7 +87,7 @@ interface GraphState {
* Type parameter refers to the `alias` property of a `TimeSeries`.
* Consequently, all series sharing the same alias will share visibility state.
*/
- hiddenSeries: Set;
+ hiddenSeries: string[];
showAllTimeSeries: boolean;
}
@@ -98,11 +96,11 @@ export class Graph extends PureComponent {
dynamicOptions = null;
state = {
- hiddenSeries: new Set(),
+ hiddenSeries: [],
showAllTimeSeries: false,
};
- getGraphData() {
+ getGraphData(): TimeSeries[] {
const { data } = this.props;
return this.state.showAllTimeSeries ? data : data.slice(0, MAX_NUMBER_OF_TIME_SERIES);
@@ -121,7 +119,7 @@ export class Graph extends PureComponent {
prevProps.split !== this.props.split ||
prevProps.height !== this.props.height ||
prevProps.width !== this.props.width ||
- !equal(prevState.hiddenSeries, this.state.hiddenSeries)
+ prevState.hiddenSeries !== this.state.hiddenSeries
) {
this.draw();
}
@@ -168,38 +166,6 @@ export class Graph extends PureComponent {
);
};
- onToggleSeries = (series: TimeSeries, exclusive: boolean) => {
- this.setState((state, props) => {
- const { data, onToggleSeries } = props;
- const { hiddenSeries } = state;
-
- // Deduplicate series as visibility tracks the alias property
- const oneSeriesVisible = hiddenSeries.size === new Set(data.map(d => d.alias)).size - 1;
-
- let nextHiddenSeries = new Set();
- if (exclusive) {
- if (hiddenSeries.has(series.alias) || !oneSeriesVisible) {
- nextHiddenSeries = new Set(data.filter(d => d.alias !== series.alias).map(d => d.alias));
- }
- } else {
- // Prune hidden series no longer part of those available from the most recent query
- const availableSeries = new Set(data.map(d => d.alias));
- nextHiddenSeries = intersect(new Set(hiddenSeries), availableSeries);
- if (nextHiddenSeries.has(series.alias)) {
- nextHiddenSeries.delete(series.alias);
- } else {
- nextHiddenSeries.add(series.alias);
- }
- }
- if (onToggleSeries) {
- onToggleSeries(series.alias, nextHiddenSeries);
- }
- return {
- hiddenSeries: nextHiddenSeries,
- };
- }, this.draw);
- };
-
draw() {
const { userOptions = {} } = this.props;
const { hiddenSeries } = this.state;
@@ -210,7 +176,7 @@ export class Graph extends PureComponent {
if (data && data.length > 0) {
series = data
- .filter((ts: TimeSeries) => !hiddenSeries.has(ts.alias))
+ .filter((ts: TimeSeries) => hiddenSeries.indexOf(ts.alias) === -1)
.map((ts: TimeSeries) => ({
color: ts.color,
label: ts.label,
@@ -229,11 +195,57 @@ export class Graph extends PureComponent {
$.plot($el, series, options);
}
- render() {
- const { height = 100, id = 'graph' } = this.props;
+ getLegendItems = (): LegendItem[] => {
const { hiddenSeries } = this.state;
const data = this.getGraphData();
+ return data.map(series => {
+ return {
+ label: series.alias,
+ color: series.color,
+ isVisible: hiddenSeries.indexOf(series.alias) === -1,
+ yAxis: 1,
+ };
+ });
+ };
+
+ onSeriesToggle(label: string, event: React.MouseEvent) {
+ // This implementation is more or less a copy of GraphPanel's logic.
+ // TODO: we need to use Graph's panel controller or split it into smaller
+ // controllers to remove code duplication. Right now we cant easily use that, since Explore
+ // is not using SeriesData for graph yet
+
+ const exclusive = event.ctrlKey || event.metaKey || event.shiftKey;
+
+ this.setState((state, props) => {
+ const { data } = props;
+ let nextHiddenSeries = [];
+ if (exclusive) {
+ // Toggling series with key makes the series itself to toggle
+ if (state.hiddenSeries.indexOf(label) > -1) {
+ nextHiddenSeries = state.hiddenSeries.filter(series => series !== label);
+ } else {
+ nextHiddenSeries = state.hiddenSeries.concat([label]);
+ }
+ } else {
+ // Toggling series with out key toggles all the series but the clicked one
+ const allSeriesLabels = data.map(series => series.label);
+
+ if (state.hiddenSeries.length + 1 === allSeriesLabels.length) {
+ nextHiddenSeries = [];
+ } else {
+ nextHiddenSeries = difference(allSeriesLabels, [label]);
+ }
+ }
+
+ return {
+ hiddenSeries: nextHiddenSeries,
+ };
+ });
+ }
+
+ render() {
+ const { height = 100, id = 'graph' } = this.props;
return (
<>
{this.props.data && this.props.data.length > MAX_NUMBER_OF_TIME_SERIES && !this.state.showAllTimeSeries && (
@@ -246,7 +258,15 @@ export class Graph extends PureComponent {
)}
-
+
+ {
+ this.onSeriesToggle(item.label, event);
+ }}
+ />
>
);
}
diff --git a/public/app/features/explore/Legend.tsx b/public/app/features/explore/Legend.tsx
deleted file mode 100644
index 3b67aa74d9173..0000000000000
--- a/public/app/features/explore/Legend.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import React, { MouseEvent, PureComponent } from 'react';
-import classNames from 'classnames';
-import { TimeSeries } from 'app/core/core';
-
-interface LegendProps {
- data: TimeSeries[];
- hiddenSeries: Set;
- onToggleSeries?: (series: TimeSeries, exclusive: boolean) => void;
-}
-
-interface LegendItemProps {
- hidden: boolean;
- onClickLabel?: (series: TimeSeries, event: MouseEvent) => void;
- series: TimeSeries;
-}
-
-class LegendItem extends PureComponent {
- onClickLabel = e => this.props.onClickLabel(this.props.series, e);
-
- render() {
- const { hidden, series } = this.props;
- const seriesClasses = classNames({
- 'graph-legend-series-hidden': hidden,
- });
- return (
-
- );
- }
-}
-
-export default class Legend extends PureComponent {
- static defaultProps = {
- onToggleSeries: () => {},
- };
-
- onClickLabel = (series: TimeSeries, event: MouseEvent) => {
- const { onToggleSeries } = this.props;
- const exclusive = event.ctrlKey || event.metaKey || event.shiftKey;
- onToggleSeries(series, !exclusive);
- };
-
- render() {
- const { data, hiddenSeries } = this.props;
- const items = data || [];
- return (
-
- {items.map((series, i) => (
-
- ))}
-
- );
- }
-}
diff --git a/public/app/features/explore/__snapshots__/Graph.test.tsx.snap b/public/app/features/explore/__snapshots__/Graph.test.tsx.snap
index c38fb26a25232..d43f94856055c 100644
--- a/public/app/features/explore/__snapshots__/Graph.test.tsx.snap
+++ b/public/app/features/explore/__snapshots__/Graph.test.tsx.snap
@@ -11,450 +11,128 @@ exports[`Render should render component 1`] = `
}
}
/>
-
`;
@@ -484,473 +162,134 @@ exports[`Render should render component with disclaimer 1`] = `
}
}
/>
-
`;
@@ -966,10 +305,11 @@ exports[`Render should show query return no time series 1`] = `
}
}
/>
-
`;
diff --git a/public/app/features/plugins/PluginPage.tsx b/public/app/features/plugins/PluginPage.tsx
index 176c03c6b6ca4..9da5b097f2a7c 100644
--- a/public/app/features/plugins/PluginPage.tsx
+++ b/public/app/features/plugins/PluginPage.tsx
@@ -74,12 +74,12 @@ interface State {
loading: boolean;
plugin?: GrafanaPlugin;
nav: NavModel;
- defaultTab: string; // The first configured one or readme
+ defaultPage: string; // The first configured one or readme
}
-const TAB_ID_README = 'readme';
-const TAB_ID_DASHBOARDS = 'dashboards';
-const TAB_ID_CONFIG_CTRL = 'config';
+const PAGE_ID_README = 'readme';
+const PAGE_ID_DASHBOARDS = 'dashboards';
+const PAGE_ID_CONFIG_CTRL = 'config';
class PluginPage extends PureComponent {
constructor(props: Props) {
@@ -87,7 +87,7 @@ class PluginPage extends PureComponent {
this.state = {
loading: true,
nav: getLoadingNav(),
- defaultTab: TAB_ID_README,
+ defaultPage: PAGE_ID_README,
};
}
@@ -103,14 +103,14 @@ class PluginPage extends PureComponent {
}
const { meta } = plugin;
- let defaultTab: string;
- const tabs: NavModelItem[] = [];
+ let defaultPage: string;
+ const pages: NavModelItem[] = [];
if (true) {
- tabs.push({
+ pages.push({
text: 'Readme',
icon: 'fa fa-fw fa-file-text-o',
- url: path + '?tab=' + TAB_ID_README,
- id: TAB_ID_README,
+ url: path + '?page=' + PAGE_ID_README,
+ id: PAGE_ID_README,
});
}
@@ -118,42 +118,42 @@ class PluginPage extends PureComponent {
if (meta.type === PluginType.app) {
// Legacy App Config
if (plugin.angularConfigCtrl) {
- tabs.push({
+ pages.push({
text: 'Config',
icon: 'gicon gicon-cog',
- url: path + '?tab=' + TAB_ID_CONFIG_CTRL,
- id: TAB_ID_CONFIG_CTRL,
+ url: path + '?page=' + PAGE_ID_CONFIG_CTRL,
+ id: PAGE_ID_CONFIG_CTRL,
});
- defaultTab = TAB_ID_CONFIG_CTRL;
+ defaultPage = PAGE_ID_CONFIG_CTRL;
}
- if (plugin.configTabs) {
- for (const tab of plugin.configTabs) {
- tabs.push({
- text: tab.title,
- icon: tab.icon,
- url: path + '?tab=' + tab.id,
- id: tab.id,
+ if (plugin.configPages) {
+ for (const page of plugin.configPages) {
+ pages.push({
+ text: page.title,
+ icon: page.icon,
+ url: path + '?page=' + page.id,
+ id: page.id,
});
- if (!defaultTab) {
- defaultTab = tab.id;
+ if (!defaultPage) {
+ defaultPage = page.id;
}
}
}
- // Check for the dashboard tabs
+ // Check for the dashboard pages
if (find(meta.includes, { type: 'dashboard' })) {
- tabs.push({
+ pages.push({
text: 'Dashboards',
icon: 'gicon gicon-dashboard',
- url: path + '?tab=' + TAB_ID_DASHBOARDS,
- id: TAB_ID_DASHBOARDS,
+ url: path + '?page=' + PAGE_ID_DASHBOARDS,
+ id: PAGE_ID_DASHBOARDS,
});
}
}
- if (!defaultTab) {
- defaultTab = tabs[0].id; // the first tab
+ if (!defaultPage) {
+ defaultPage = pages[0].id; // the first tab
}
const node = {
@@ -162,13 +162,13 @@ class PluginPage extends PureComponent {
subTitle: meta.info.author.name,
breadcrumbs: [{ title: 'Plugins', url: '/plugins' }],
url: path,
- children: this.setActiveTab(query.tab as string, tabs, defaultTab),
+ children: this.setActivePage(query.page as string, pages, defaultPage),
};
this.setState({
loading: false,
plugin,
- defaultTab,
+ defaultPage,
nav: {
node: node,
main: node,
@@ -176,15 +176,15 @@ class PluginPage extends PureComponent {
});
}
- setActiveTab(tabId: string, tabs: NavModelItem[], defaultTabId: string): NavModelItem[] {
+ setActivePage(pageId: string, pages: NavModelItem[], defaultPageId: string): NavModelItem[] {
let found = false;
- const selected = tabId || defaultTabId;
- const changed = tabs.map(tab => {
- const active = !found && selected === tab.id;
+ const selected = pageId || defaultPageId;
+ const changed = pages.map(p => {
+ const active = !found && selected === p.id;
if (active) {
found = true;
}
- return { ...tab, active };
+ return { ...p, active };
});
if (!found) {
changed[0].active = true;
@@ -193,13 +193,13 @@ class PluginPage extends PureComponent {
}
componentDidUpdate(prevProps: Props) {
- const prevTab = prevProps.query.tab as string;
- const tab = this.props.query.tab as string;
- if (prevTab !== tab) {
- const { nav, defaultTab } = this.state;
+ const prevPage = prevProps.query.page as string;
+ const page = this.props.query.page as string;
+ if (prevPage !== page) {
+ const { nav, defaultPage } = this.state;
const node = {
...nav.node,
- children: this.setActiveTab(tab, nav.node.children, defaultTab),
+ children: this.setActivePage(page, nav.node.children, defaultPage),
};
this.setState({
nav: {
@@ -221,21 +221,21 @@ class PluginPage extends PureComponent {
const active = nav.main.children.find(tab => tab.active);
if (active) {
// Find the current config tab
- if (plugin.configTabs) {
- for (const tab of plugin.configTabs) {
+ if (plugin.configPages) {
+ for (const tab of plugin.configPages) {
if (tab.id === active.id) {
- return ;
+ return ;
}
}
}
// Apps have some special behavior
if (plugin.meta.type === PluginType.app) {
- if (active.id === TAB_ID_DASHBOARDS) {
+ if (active.id === PAGE_ID_DASHBOARDS) {
return ;
}
- if (active.id === TAB_ID_CONFIG_CTRL && plugin.angularConfigCtrl) {
+ if (active.id === PAGE_ID_CONFIG_CTRL && plugin.angularConfigCtrl) {
return ;
}
}
diff --git a/public/app/plugins/app/example-app/config/ExampleTab1.tsx b/public/app/plugins/app/example-app/config/ExamplePage1.tsx
similarity index 65%
rename from public/app/plugins/app/example-app/config/ExampleTab1.tsx
rename to public/app/plugins/app/example-app/config/ExamplePage1.tsx
index cf79a880f435a..c25eee35e535c 100644
--- a/public/app/plugins/app/example-app/config/ExampleTab1.tsx
+++ b/public/app/plugins/app/example-app/config/ExamplePage1.tsx
@@ -2,11 +2,11 @@
import React, { PureComponent } from 'react';
// Types
-import { PluginConfigTabProps, AppPluginMeta } from '@grafana/ui';
+import { PluginConfigPageProps, AppPlugin } from '@grafana/ui';
-interface Props extends PluginConfigTabProps {}
+interface Props extends PluginConfigPageProps {}
-export class ExampleTab1 extends PureComponent {
+export class ExamplePage1 extends PureComponent {
constructor(props: Props) {
super(props);
}
diff --git a/public/app/plugins/app/example-app/config/ExampleTab2.tsx b/public/app/plugins/app/example-app/config/ExamplePage2.tsx
similarity index 65%
rename from public/app/plugins/app/example-app/config/ExampleTab2.tsx
rename to public/app/plugins/app/example-app/config/ExamplePage2.tsx
index bf2ae181405a7..596bb88e9ba07 100644
--- a/public/app/plugins/app/example-app/config/ExampleTab2.tsx
+++ b/public/app/plugins/app/example-app/config/ExamplePage2.tsx
@@ -2,11 +2,11 @@
import React, { PureComponent } from 'react';
// Types
-import { PluginConfigTabProps, AppPluginMeta } from '@grafana/ui';
+import { PluginConfigPageProps, AppPlugin } from '@grafana/ui';
-interface Props extends PluginConfigTabProps {}
+interface Props extends PluginConfigPageProps {}
-export class ExampleTab2 extends PureComponent {
+export class ExamplePage2 extends PureComponent {
constructor(props: Props) {
super(props);
}
diff --git a/public/app/plugins/app/example-app/module.ts b/public/app/plugins/app/example-app/module.ts
index 0b4a2ae646a92..f82f7faec08b5 100644
--- a/public/app/plugins/app/example-app/module.ts
+++ b/public/app/plugins/app/example-app/module.ts
@@ -2,8 +2,8 @@
import { ExampleConfigCtrl } from './legacy/config';
import { AngularExamplePageCtrl } from './legacy/angular_example_page';
import { AppPlugin } from '@grafana/ui';
-import { ExampleTab1 } from './config/ExampleTab1';
-import { ExampleTab2 } from './config/ExampleTab2';
+import { ExamplePage1 } from './config/ExamplePage1';
+import { ExamplePage2 } from './config/ExamplePage2';
import { ExampleRootPage } from './ExampleRootPage';
// Legacy exports just for testing
@@ -14,15 +14,15 @@ export {
export const plugin = new AppPlugin()
.setRootPage(ExampleRootPage)
- .addConfigTab({
- title: 'Tab 1',
+ .addConfigPage({
+ title: 'Page 1',
icon: 'fa fa-info',
- body: ExampleTab1,
- id: 'tab1',
+ body: ExamplePage1,
+ id: 'page1',
})
- .addConfigTab({
- title: 'Tab 2',
+ .addConfigPage({
+ title: 'Page 2',
icon: 'fa fa-user',
- body: ExampleTab2,
- id: 'tab2',
+ body: ExamplePage2,
+ id: 'page2',
});
diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html b/public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html
index c2461eb67ead1..6761502dd2a21 100644
--- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html
+++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/query.editor.html
@@ -108,17 +108,18 @@
-
-
-
-
-
-
-
-
diff --git a/public/app/plugins/datasource/testdata/TestInfoTab.tsx b/public/app/plugins/datasource/testdata/TestInfoTab.tsx
new file mode 100644
index 0000000000000..686d8b94e4aba
--- /dev/null
+++ b/public/app/plugins/datasource/testdata/TestInfoTab.tsx
@@ -0,0 +1,28 @@
+// Libraries
+import React, { PureComponent } from 'react';
+
+// Types
+import { PluginConfigPageProps, DataSourcePlugin } from '@grafana/ui';
+import { TestDataDatasource } from './datasource';
+
+interface Props extends PluginConfigPageProps> {}
+
+export class TestInfoTab extends PureComponent {
+ constructor(props: Props) {
+ super(props);
+ }
+
+ render() {
+ return (
+
+ See github for more information about setting up a reproducable test environment.
+
+
+
+ Github
+
+
+
+ );
+ }
+}
diff --git a/public/app/plugins/datasource/testdata/module.tsx b/public/app/plugins/datasource/testdata/module.tsx
index 738149451b978..800f61db73708 100644
--- a/public/app/plugins/datasource/testdata/module.tsx
+++ b/public/app/plugins/datasource/testdata/module.tsx
@@ -1,6 +1,7 @@
import { DataSourcePlugin } from '@grafana/ui';
import { TestDataDatasource } from './datasource';
import { TestDataQueryCtrl } from './query_ctrl';
+import { TestInfoTab } from './TestInfoTab';
import { ConfigEditor } from './ConfigEditor';
class TestDataAnnotationsQueryCtrl {
@@ -12,4 +13,10 @@ class TestDataAnnotationsQueryCtrl {
export const plugin = new DataSourcePlugin(TestDataDatasource)
.setConfigEditor(ConfigEditor)
.setQueryCtrl(TestDataQueryCtrl)
- .setAnnotationQueryCtrl(TestDataAnnotationsQueryCtrl);
+ .setAnnotationQueryCtrl(TestDataAnnotationsQueryCtrl)
+ .addConfigPage({
+ title: 'Setup',
+ icon: 'fa fa-list-alt',
+ body: TestInfoTab,
+ id: 'setup',
+ });
diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx
index 0c82402568387..b08b49f01bf4e 100644
--- a/public/app/plugins/panel/gauge/GaugePanel.tsx
+++ b/public/app/plugins/panel/gauge/GaugePanel.tsx
@@ -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> {
};
render() {
- const { height, width, options, data, renderCounter } = this.props;
+ const { height, width, data, renderCounter } = this.props;
return (
> {
height={height}
source={data}
renderCounter={renderCounter}
- orientation={options.orientation}
+ orientation={VizOrientation.Auto}
/>
);
}
diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts
index 9a7c9b5d2d50a..a863797dea04f 100644
--- a/public/app/routes/routes.ts
+++ b/public/app/routes/routes.ts
@@ -110,6 +110,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
})
.when('/datasources/edit/:id/', {
template: '',
+ reloadOnSearch: false, // for tabs
resolve: {
component: () => DataSourceSettingsPage,
},
diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss
index 1fe950f8e53e5..38b8533ee4701 100644
--- a/public/sass/components/_search.scss
+++ b/public/sass/components/_search.scss
@@ -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;
}