diff --git a/.gitignore b/.gitignore
index 188313e..5882751 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,6 @@
node_modules
npm-debug.log
-dist/
-
.idea/
*.iml
diff --git a/dist/README.adoc b/dist/README.adoc
new file mode 100644
index 0000000..8b8e4d2
--- /dev/null
+++ b/dist/README.adoc
@@ -0,0 +1,78 @@
+= Hawkular Datasource for Grafana
+:source-language: javascript
+
+This project is the Hawkular Datasource plugin for Grafana 3. It works with:
+
+* Metrics standalone servers as well
+* Hawkular servers, starting from version Alpha13
+
+== Installing
+
+=== From source
+
+Download the source code and copy the content of `dist` to `hawkular` inside Grafana's plugin directory.
+
+[source,bash]
+----
+# This is the default for Linux Grafana installs. Change it to match yours, if needed.
+GRAFANA_PLUGINS=/var/lib/grafana/plugins
+wget https://github.com/hawkular/hawkular-grafana-datasource/archive/master.zip -O hawkular-grafana-datasource-master.zip
+unzip hawkular-grafana-datasource-master.zip
+mkdir ${GRAFANA_PLUGINS}/hawkular
+cp -R hawkular-grafana-datasource-master/dist/* ${GRAFANA_PLUGINS}/hawkular
+----
+
+=== From the Grafana plugin directory
+
+COMING SOON
+
+== Configuration
+
+The datasource URL must point to the Hawkular Metrics service, e.g. `http://myhost:8080/hawkular/metrics`
+
+`direct` access mode only works with standalone Metrics servers currently. If you active it, make sure to allow
+the Grafana server origin in Metrics' configuration.
+
+Authentication must be set when working with a Hawkular server. Check the 'Basic Auth' box and fill the user and password fields.
+
+Select the tenant. On Hawkular servers, use `hawkular`.
+
+Openshift-Metrics users must provide an authentication token.
+
+== Using Grafana Templating (variables)
+
+Grafana allows you to create dashboard templates through the definition of variables. This is link:http://docs.grafana.org/reference/templating/[documented on Grafana's site].
+With the Hawkular Datasource Plugin, the variables of type _'Query'_ are mapped to the http://www.hawkular.org/docs/rest/rest-metrics.html#GET__metrics[_@get (url)/metrics_]
+Hawkular Metrics endpoint and can be used to retrieve tenant's metric names. Use the _Query Options_ text field to pass query parameters.
+[TIP]
+For instance, if you have metrics tagged _"type:memory"_ and others tagged _"type:cpu"_, you can write _"?tags=type:memory"_ to get only the _"memory"_ ones, or _"?tags=type:cpu|memory"_ to get them both. The leading question mark is not mandatory.
+
+There is an exception to that rule: if the query string is prefixed with _'tags/'_, the variable will contain the matching tag names rather than the metric names. In this case, the Hawkular Metrics endpoint link:++http://www.hawkular.org/docs/rest/rest-metrics.html#GET__metrics_tags__tags_++[_@get (url)/metrics/tags/{tags}_] will be used.
+[TIP]
+For instance, type _"tags/type:*"_ to get all of the available tag values for _"type"_.
+
+Once you have set some variables, you can use them in graph queries: either for row or graph duplication, or to display multiple series in a single graph from a single query. This is especially useful when metric names contain some dynamic parts and thus cannot be known in advance.
+
+== Building
+
+You need `npm` and `grunt` to build the project. Clone this repository, then from that directory run:
+
+[source,bash]
+----
+npm install
+grunt
+----
+
+Files are generated under the `dist` directory.
+
+To test it, copy these files to `${GRAFANA_PLUGINS}/hawkular` and restart grafana-server.
+
+== Building and running a Docker image
+
+[source,bash]
+----
+# This will build the image
+docker build -t hawkular/hawkular-grafana-datasource .
+# This will run the image on http://localhost:3000/
+docker run -i -p 3000:3000 --name hawkular-grafana-datasource --rm hawkular/hawkular-grafana-datasource
+----
diff --git a/dist/capabilities.js b/dist/capabilities.js
new file mode 100644
index 0000000..2520c7a
--- /dev/null
+++ b/dist/capabilities.js
@@ -0,0 +1,40 @@
+'use strict';
+
+System.register([], function (_export, _context) {
+ "use strict";
+
+ var Capabilities;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [],
+ execute: function () {
+ _export('Capabilities', Capabilities = function Capabilities(versionStr) {
+ _classCallCheck(this, Capabilities);
+
+ this.QUERY_POST_ENDPOINTS = true;
+ this.QUERY_BY_TAGS = true;
+ var regExp = new RegExp('([0-9]+)\.([0-9]+)\.(.+)');
+ if (versionStr.match(regExp)) {
+ var versionInfo = regExp.exec(versionStr);
+ var major = versionInfo[1];
+ var minor = versionInfo[2];
+ if (major == 0 && minor < 17) {
+ this.QUERY_POST_ENDPOINTS = false;
+ }
+ if (major == 0 && minor < 20) {
+ this.QUERY_BY_TAGS = false;
+ }
+ }
+ });
+
+ _export('Capabilities', Capabilities);
+ }
+ };
+});
+//# sourceMappingURL=capabilities.js.map
diff --git a/dist/capabilities.js.map b/dist/capabilities.js.map
new file mode 100644
index 0000000..8f72a52
--- /dev/null
+++ b/dist/capabilities.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/capabilities.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;8BAAa,Y,GAEX,sBAAY,UAAZ,EAAwB;AAAA;;AACtB,aAAK,oBAAL,GAA4B,IAA5B;AACA,aAAK,aAAL,GAAqB,IAArB;AACA,YAAI,SAAS,IAAI,MAAJ,CAAW,0BAAX,CAAb;AACA,YAAI,WAAW,KAAX,CAAiB,MAAjB,CAAJ,EAA8B;AAC5B,cAAI,cAAc,OAAO,IAAP,CAAY,UAAZ,CAAlB;AACA,cAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,cAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,cAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,iBAAK,oBAAL,GAA4B,KAA5B;AACD;AACD,cAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,iBAAK,aAAL,GAAqB,KAArB;AACD;AACF;AACF,O","file":"capabilities.js","sourcesContent":["export class Capabilities {\n\n constructor(versionStr) {\n this.QUERY_POST_ENDPOINTS = true;\n this.QUERY_BY_TAGS = true;\n let regExp = new RegExp('([0-9]+)\\.([0-9]+)\\.(.+)');\n if (versionStr.match(regExp)) {\n let versionInfo = regExp.exec(versionStr);\n let major = versionInfo[1];\n let minor = versionInfo[2];\n if (major == 0 && minor < 17) {\n this.QUERY_POST_ENDPOINTS = false;\n }\n if (major == 0 && minor < 20) {\n this.QUERY_BY_TAGS = false;\n }\n }\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/css/query-editor.css b/dist/css/query-editor.css
new file mode 100644
index 0000000..3b678b9
--- /dev/null
+++ b/dist/css/query-editor.css
@@ -0,0 +1,3 @@
+.generic-datasource-query-row .query-keyword {
+ width: 75px;
+}
\ No newline at end of file
diff --git a/dist/datasource.js b/dist/datasource.js
new file mode 100644
index 0000000..6dbf885
--- /dev/null
+++ b/dist/datasource.js
@@ -0,0 +1,226 @@
+'use strict';
+
+System.register(['lodash', './variables', './capabilities', './queryProcessor'], function (_export, _context) {
+ "use strict";
+
+ var _, Variables, Capabilities, QueryProcessor, _createClass, HawkularDatasource;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [function (_lodash) {
+ _ = _lodash.default;
+ }, function (_variables) {
+ Variables = _variables.Variables;
+ }, function (_capabilities) {
+ Capabilities = _capabilities.Capabilities;
+ }, function (_queryProcessor) {
+ QueryProcessor = _queryProcessor.QueryProcessor;
+ }],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('HawkularDatasource', HawkularDatasource = function () {
+ function HawkularDatasource(instanceSettings, $q, backendSrv, templateSrv) {
+ _classCallCheck(this, HawkularDatasource);
+
+ this.type = instanceSettings.type;
+ this.url = instanceSettings.url;
+ this.name = instanceSettings.name;
+ this.tenant = instanceSettings.jsonData.tenant;
+ this.token = instanceSettings.jsonData.token;
+ this.q = $q;
+ this.backendSrv = backendSrv;
+ var variables = new Variables(templateSrv);
+ this.capabilitiesPromise = this.queryVersion().then(function (version) {
+ return new Capabilities(version);
+ });
+ this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());
+ }
+
+ _createClass(HawkularDatasource, [{
+ key: 'query',
+ value: function query(options) {
+ var _this = this;
+
+ var validTargets = options.targets.filter(function (target) {
+ return !target.hide;
+ }).filter(function (target) {
+ return target.target !== 'select metric';
+ });
+
+ if (validTargets.length === 0) {
+ return this.q.when({ data: [] });
+ }
+
+ var promises = validTargets.map(function (target) {
+ return _this.queryProcessor.run(target, options);
+ });
+
+ return this.q.all(promises).then(function (responses) {
+ var flatten = [].concat.apply([], responses);
+ return { data: flatten };
+ });
+ }
+ }, {
+ key: 'createHeaders',
+ value: function createHeaders() {
+ var headers = {
+ 'Content-Type': 'application/json',
+ 'Hawkular-Tenant': this.tenant
+ };
+ if (typeof this.token === 'string' && this.token.length > 0) {
+ headers.Authorization = 'Bearer ' + this.token;
+ }
+ return headers;
+ }
+ }, {
+ key: 'testDatasource',
+ value: function testDatasource() {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/status',
+ method: 'GET'
+ }).then(function (response) {
+ if (response.status === 200) {
+ return { status: "success", message: "Data source is working", title: "Success" };
+ }
+ });
+ }
+ }, {
+ key: 'annotationQuery',
+ value: function annotationQuery(options) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/annotations',
+ method: 'POST',
+ data: options
+ }).then(function (result) {
+ return result.data;
+ });
+ }
+ }, {
+ key: 'suggestQueries',
+ value: function suggestQueries(target) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics?type=' + target.type,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ return _.map(result.data, function (metric) {
+ return { text: metric.id, value: metric.id };
+ });
+ });
+ }
+ }, {
+ key: 'suggestTags',
+ value: function suggestTags(type, key) {
+ if (!key) {
+ // Need at least some characters typed in order to suggest something
+ return this.q.when([]);
+ }
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/' + type + 's/tags/' + key + ':*',
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ if (result.data.hasOwnProperty(key)) {
+ return [' *'].concat(result.data[key]).map(function (value) {
+ return { text: value, value: value };
+ });
+ }
+ return [];
+ });
+ }
+ }, {
+ key: 'metricFindQuery',
+ value: function metricFindQuery(query) {
+ var params = "";
+ if (query !== undefined) {
+ if (query.startsWith("tags/")) {
+ return this.findTags(query.substr(5).trim());
+ }
+ if (query.startsWith("?")) {
+ params = query;
+ } else {
+ params = "?" + query;
+ }
+ }
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics' + params,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ return _.map(result.data, function (metric) {
+ return { text: metric.id, value: metric.id };
+ });
+ });
+ }
+ }, {
+ key: 'findTags',
+ value: function findTags(pattern) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics/tags/' + pattern,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ var flatTags = [];
+ if (result.data) {
+ var data = result.data;
+ for (var property in data) {
+ if (data.hasOwnProperty(property)) {
+ flatTags = flatTags.concat(data[property]);
+ }
+ }
+ }
+ return flatTags.map(function (tag) {
+ return { text: tag, value: tag };
+ });
+ });
+ }
+ }, {
+ key: 'queryVersion',
+ value: function queryVersion() {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/status',
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function (response) {
+ return response.data['Implementation-Version'];
+ }).catch(function (response) {
+ return "Unknown";
+ });
+ }
+ }, {
+ key: 'getCapabilities',
+ value: function getCapabilities() {
+ return this.capabilitiesPromise;
+ }
+ }]);
+
+ return HawkularDatasource;
+ }());
+
+ _export('HawkularDatasource', HawkularDatasource);
+ }
+ };
+});
+//# sourceMappingURL=datasource.js.map
diff --git a/dist/datasource.js.map b/dist/datasource.js.map
new file mode 100644
index 0000000..2b4e6bc
--- /dev/null
+++ b/dist/datasource.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/datasource.js"],"names":[],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\nimport {Variables} from './variables';\nimport {Capabilities} from './capabilities';\nimport {QueryProcessor} from './queryProcessor';\n\nexport class HawkularDatasource {\n\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.type = instanceSettings.type;\n this.url = instanceSettings.url;\n this.name = instanceSettings.name;\n this.tenant = instanceSettings.jsonData.tenant;\n this.token = instanceSettings.jsonData.token;\n this.q = $q;\n this.backendSrv = backendSrv;\n let variables = new Variables(templateSrv);\n this.capabilitiesPromise = this.queryVersion()\n .then(version => new Capabilities(version));\n this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());\n }\n\n query(options) {\n let validTargets = options.targets\n .filter(target => !target.hide)\n .filter(target => target.target !== 'select metric');\n\n if (validTargets.length === 0) {\n return this.q.when({data: []});\n }\n\n let promises = validTargets.map(target => {\n return this.queryProcessor.run(target, options);\n });\n\n return this.q.all(promises).then(responses => {\n let flatten = [].concat.apply([], responses);\n return {data: flatten};\n });\n }\n\n createHeaders() {\n var headers = {\n 'Content-Type': 'application/json',\n 'Hawkular-Tenant': this.tenant\n };\n if (typeof this.token === 'string' && this.token.length > 0) {\n headers.Authorization = 'Bearer ' + this.token;\n }\n return headers;\n }\n\n testDatasource() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET'\n }).then(response => {\n if (response.status === 200) {\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\n }\n });\n }\n\n annotationQuery(options) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/annotations',\n method: 'POST',\n data: options\n }).then(result => {\n return result.data;\n });\n }\n\n suggestQueries(target) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics?type=' + target.type,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n suggestTags(type, key) {\n if (!key) {\n // Need at least some characters typed in order to suggest something\n return this.q.when([]);\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/' + type + 's/tags/' + key + ':*',\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n if (result.data.hasOwnProperty(key)) {\n return [' *'].concat(result.data[key]).map(value => {\n return {text: value, value: value};\n });\n }\n return [];\n });\n }\n\n metricFindQuery(query) {\n var params = \"\";\n if (query !== undefined) {\n if (query.startsWith(\"tags/\")) {\n return this.findTags(query.substr(5).trim());\n }\n if (query.startsWith(\"?\")) {\n params = query;\n } else {\n params = \"?\" + query;\n }\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics' + params,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n findTags(pattern) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics/tags/' + pattern,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n var flatTags = [];\n if (result.data) {\n var data = result.data;\n for (var property in data) {\n if (data.hasOwnProperty(property)) {\n flatTags = flatTags.concat(data[property]);\n }\n }\n }\n return flatTags.map(tag => {\n return {text: tag, value: tag};\n });\n });\n }\n\n queryVersion() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET',\n headers: {'Content-Type': 'application/json'}\n }).then(response => response.data['Implementation-Version'])\n .catch(response => \"Unknown\");\n }\n\n getCapabilities() {\n return this.capabilitiesPromise;\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/img/hawkular_logo.svg b/dist/img/hawkular_logo.svg
new file mode 100644
index 0000000..b8a46a3
--- /dev/null
+++ b/dist/img/hawkular_logo.svg
@@ -0,0 +1,69 @@
+
+
+
+
diff --git a/dist/module.js b/dist/module.js
new file mode 100644
index 0000000..8dc62fe
--- /dev/null
+++ b/dist/module.js
@@ -0,0 +1,51 @@
+'use strict';
+
+System.register(['./datasource', './query_ctrl'], function (_export, _context) {
+ "use strict";
+
+ var HawkularDatasource, HawkularDatasourceQueryCtrl, HawkularConfigCtrl, HawkularQueryOptionsCtrl, HawkularAnnotationsQueryCtrl;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [function (_datasource) {
+ HawkularDatasource = _datasource.HawkularDatasource;
+ }, function (_query_ctrl) {
+ HawkularDatasourceQueryCtrl = _query_ctrl.HawkularDatasourceQueryCtrl;
+ }],
+ execute: function () {
+ _export('ConfigCtrl', HawkularConfigCtrl = function HawkularConfigCtrl() {
+ _classCallCheck(this, HawkularConfigCtrl);
+ });
+
+ HawkularConfigCtrl.templateUrl = 'partials/config.html';
+
+ _export('QueryOptionsCtrl', HawkularQueryOptionsCtrl = function HawkularQueryOptionsCtrl() {
+ _classCallCheck(this, HawkularQueryOptionsCtrl);
+ });
+
+ HawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';
+
+ _export('AnnotationsQueryCtrl', HawkularAnnotationsQueryCtrl = function HawkularAnnotationsQueryCtrl() {
+ _classCallCheck(this, HawkularAnnotationsQueryCtrl);
+ });
+
+ HawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';
+
+ _export('Datasource', HawkularDatasource);
+
+ _export('QueryCtrl', HawkularDatasourceQueryCtrl);
+
+ _export('ConfigCtrl', HawkularConfigCtrl);
+
+ _export('QueryOptionsCtrl', HawkularQueryOptionsCtrl);
+
+ _export('AnnotationsQueryCtrl', HawkularAnnotationsQueryCtrl);
+ }
+ };
+});
+//# sourceMappingURL=module.js.map
diff --git a/dist/module.js.map b/dist/module.js.map
new file mode 100644
index 0000000..51a2f0d
--- /dev/null
+++ b/dist/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/module.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAQ,wB,eAAA,kB;;AACA,iC,eAAA,2B;;;4BAEF,kB;;;;AACN,yBAAmB,WAAnB,GAAiC,sBAAjC;;kCAEM,wB;;;;AACN,+BAAyB,WAAzB,GAAuC,6BAAvC;;sCAEM,4B;;;;AACN,mCAA6B,WAA7B,GAA2C,kCAA3C;;4BAGE,kB;;2BACA,2B;;4BACA,kB;;kCACA,wB;;sCACA,4B","file":"module.js","sourcesContent":["import {HawkularDatasource} from './datasource';\nimport {HawkularDatasourceQueryCtrl} from './query_ctrl';\n\nclass HawkularConfigCtrl {}\nHawkularConfigCtrl.templateUrl = 'partials/config.html';\n\nclass HawkularQueryOptionsCtrl {}\nHawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\n\nclass HawkularAnnotationsQueryCtrl {}\nHawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';\n\nexport {\n HawkularDatasource as Datasource,\n HawkularDatasourceQueryCtrl as QueryCtrl,\n HawkularConfigCtrl as ConfigCtrl,\n HawkularQueryOptionsCtrl as QueryOptionsCtrl,\n HawkularAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]}
\ No newline at end of file
diff --git a/dist/partials/annotations.editor.html b/dist/partials/annotations.editor.html
new file mode 100644
index 0000000..8e67e97
--- /dev/null
+++ b/dist/partials/annotations.editor.html
@@ -0,0 +1,9 @@
+
+
Query
+
+
+
diff --git a/dist/partials/config.html b/dist/partials/config.html
new file mode 100644
index 0000000..f17bc93
--- /dev/null
+++ b/dist/partials/config.html
@@ -0,0 +1,19 @@
+
+
+
+Hawkular settings
+
+
diff --git a/dist/partials/query.editor.html b/dist/partials/query.editor.html
new file mode 100644
index 0000000..cdeb273
--- /dev/null
+++ b/dist/partials/query.editor.html
@@ -0,0 +1,21 @@
+
+
+
diff --git a/dist/partials/query.options.html b/dist/partials/query.options.html
new file mode 100644
index 0000000..b460011
--- /dev/null
+++ b/dist/partials/query.options.html
@@ -0,0 +1,4 @@
+
diff --git a/dist/plugin.json b/dist/plugin.json
new file mode 100644
index 0000000..6a75da7
--- /dev/null
+++ b/dist/plugin.json
@@ -0,0 +1,34 @@
+{
+ "id": "hawkular",
+ "type": "datasource",
+ "name": "Hawkular",
+ "metrics": true,
+ "annotations": false,
+ "info": {
+ "description": "Hawkular Datasource",
+ "author": {
+ "name": "Hawkular Project",
+ "url": "http://hawkular.org"
+ },
+ "logos": {
+ "small": "img/hawkular_logo.svg",
+ "large": "img/hawkular_logo.svg"
+ },
+ "links": [
+ {
+ "name": "Project",
+ "url": "http://hawkular.org"
+ },
+ {
+ "name": "GitHub",
+ "url": "https://github.com/hawkular/hawkular-grafana-datasource"
+ }
+ ],
+ "version": "1.0.0",
+ "updated": "2016-05-30"
+ },
+ "dependencies": {
+ "grafanaVersion": "3.x.x",
+ "plugins": []
+ }
+}
diff --git a/dist/queryProcessor.js b/dist/queryProcessor.js
new file mode 100644
index 0000000..a09ed53
--- /dev/null
+++ b/dist/queryProcessor.js
@@ -0,0 +1,210 @@
+'use strict';
+
+System.register([], function (_export, _context) {
+ "use strict";
+
+ var _createClass, QueryProcessor;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('QueryProcessor', QueryProcessor = function () {
+ function QueryProcessor(q, backendSrv, variables, capabilities, url, baseHeaders) {
+ _classCallCheck(this, QueryProcessor);
+
+ this.q = q;
+ this.backendSrv = backendSrv;
+ this.variables = variables;
+ this.capabilities = capabilities;
+ this.url = url;
+ this.baseHeaders = baseHeaders;
+ }
+
+ _createClass(QueryProcessor, [{
+ key: 'run',
+ value: function run(target, options) {
+ var _this = this;
+
+ return this.capabilities.then(function (caps) {
+ if (target.queryBy === 'ids') {
+ var metricIds = _this.variables.resolve(target.target, options);
+ if (caps.QUERY_POST_ENDPOINTS) {
+ return _this.rawQuery(target, options.range, metricIds);
+ } else {
+ return _this.rawQueryLegacy(target, options.range, metricIds);
+ }
+ } else {
+ if (target.tags.length === 0) {
+ return _this.q.when([]);
+ }
+ var strTags = _this.hawkularFormatTags(target.tags, options);
+ return _this.rawQueryByTags(target, options.range, strTags);
+ }
+ });
+ }
+ }, {
+ key: 'hawkularFormatTags',
+ value: function hawkularFormatTags(tags, options) {
+ var _this2 = this;
+
+ return tags.map(function (tag) {
+ var value;
+ if (tag.value === ' *') {
+ // '*' character get a special treatment in grafana so we had to use ' *' instead
+ value = '*';
+ } else {
+ value = _this2.variables.resolve(tag.value, options).join('|');
+ }
+ return tag.name + ':' + value;
+ }).join(',');
+ }
+ }, {
+ key: 'rawQuery',
+ value: function rawQuery(target, range, metricIds) {
+ var _this3 = this;
+
+ var uri = [target.type + 's', // gauges or counters
+ target.rate ? 'rate' : 'raw', // raw or rate
+ 'query'];
+ var url = this.url + '/' + uri.join('/');
+
+ return this.backendSrv.datasourceRequest({
+ url: url,
+ data: {
+ ids: metricIds,
+ start: range.from.valueOf(),
+ end: range.to.valueOf(),
+ order: 'ASC'
+ },
+ method: 'POST',
+ headers: this.baseHeaders
+ }).then(function (response) {
+ return _this3.processRawResponse(target, response.status == 200 ? response.data : []);
+ });
+ }
+ }, {
+ key: 'rawQueryLegacy',
+ value: function rawQueryLegacy(target, range, metricIds) {
+ var _this4 = this;
+
+ return this.q.all(metricIds.map(function (metric) {
+ var uri = [target.type + 's', // gauges or counters
+ encodeURIComponent(metric).replace('+', '%20'), // metric name
+ 'data'];
+ var url = _this4.url + '/' + uri.join('/');
+
+ return _this4.backendSrv.datasourceRequest({
+ url: url,
+ params: {
+ start: range.from.valueOf(),
+ end: range.to.valueOf()
+ },
+ method: 'GET',
+ headers: _this4.baseHeaders
+ }).then(function (response) {
+ return _this4.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []);
+ });
+ }));
+ }
+ }, {
+ key: 'rawQueryByTags',
+ value: function rawQueryByTags(target, range, tags) {
+ var _this5 = this;
+
+ var uri = [target.type + 's', // gauges or counters
+ target.rate ? 'rate' : 'raw', // raw or rate
+ 'query'];
+ var url = this.url + '/' + uri.join('/');
+
+ return this.backendSrv.datasourceRequest({
+ url: url,
+ data: {
+ tags: tags,
+ start: range.from.valueOf(),
+ end: range.to.valueOf(),
+ order: 'ASC'
+ },
+ method: 'POST',
+ headers: this.baseHeaders
+ }).then(function (response) {
+ return _this5.processRawResponse(target, response.status == 200 ? response.data : []);
+ });
+ }
+ }, {
+ key: 'processRawResponse',
+ value: function processRawResponse(target, data) {
+ return data.map(function (timeSerie) {
+ return {
+ refId: target.refId,
+ target: timeSerie.id,
+ datapoints: timeSerie.data.map(function (point) {
+ return [point.value, point.timestamp];
+ })
+ };
+ });
+ }
+ }, {
+ key: 'processRawResponseLegacy',
+ value: function processRawResponseLegacy(target, metric, data) {
+ var datapoints;
+ if (!target.rate) {
+ datapoints = _.map(data, function (point) {
+ return [point.value, point.timestamp];
+ });
+ } else {
+ var sortedData = data.sort(function (p1, p2) {
+ return p1.timestamp - p2.timestamp;
+ });
+ datapoints = _.chain(sortedData).zip(sortedData.slice(1)).filter(function (pair) {
+ return pair[1] // Exclude the last pair
+ && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets
+ }).map(function (pair) {
+ var point1 = pair[0],
+ point2 = pair[1];
+ var timestamp = point2.timestamp;
+ var value_diff = point2.value - point1.value;
+ var time_diff = point2.timestamp - point1.timestamp;
+ var rate = 60000 * value_diff / time_diff;
+ return [rate, timestamp];
+ }).value();
+ }
+ return {
+ refId: target.refId,
+ target: metric,
+ datapoints: datapoints
+ };
+ }
+ }]);
+
+ return QueryProcessor;
+ }());
+
+ _export('QueryProcessor', QueryProcessor);
+ }
+ };
+});
+//# sourceMappingURL=queryProcessor.js.map
diff --git a/dist/queryProcessor.js.map b/dist/queryProcessor.js.map
new file mode 100644
index 0000000..5b360dd
--- /dev/null
+++ b/dist/queryProcessor.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/queryProcessor.js"],"names":[],"mappings":"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","file":"queryProcessor.js","sourcesContent":["export class QueryProcessor {\n\n constructor(q, backendSrv, variables, capabilities, url, baseHeaders) {\n this.q = q;\n this.backendSrv = backendSrv;\n this.variables = variables;\n this.capabilities = capabilities;\n this.url = url;\n this.baseHeaders = baseHeaders;\n }\n\n run(target, options) {\n return this.capabilities.then(caps => {\n if (target.queryBy === 'ids') {\n let metricIds = this.variables.resolve(target.target, options);\n if (caps.QUERY_POST_ENDPOINTS) {\n return this.rawQuery(target, options.range, metricIds);\n } else {\n return this.rawQueryLegacy(target, options.range, metricIds);\n }\n } else {\n if (target.tags.length === 0) {\n return this.q.when([]);\n }\n let strTags = this.hawkularFormatTags(target.tags, options);\n return this.rawQueryByTags(target, options.range, strTags);\n }\n });\n }\n\n hawkularFormatTags(tags, options) {\n return tags.map(tag => {\n var value;\n if (tag.value === ' *') {\n // '*' character get a special treatment in grafana so we had to use ' *' instead\n value = '*';\n } else {\n value = this.variables.resolve(tag.value, options).join('|');\n }\n return tag.name + ':' + value;\n }).join(',');\n }\n\n rawQuery(target, range, metricIds) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n ids: metricIds,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n rawQueryLegacy(target, range, metricIds) {\n return this.q.all(metricIds.map(metric => {\n let uri = [\n target.type + 's', // gauges or counters\n encodeURIComponent(metric).replace('+', '%20'), // metric name\n 'data'];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n params: {\n start: range.from.valueOf(),\n end: range.to.valueOf()\n },\n method: 'GET',\n headers: this.baseHeaders\n }).then(response => this.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []));\n }));\n }\n\n rawQueryByTags(target, range, tags) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n tags: tags,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n processRawResponse(target, data) {\n return data.map(timeSerie => {\n return {\n refId: target.refId,\n target: timeSerie.id,\n datapoints: timeSerie.data.map(point => [point.value, point.timestamp])\n };\n });\n }\n\n processRawResponseLegacy(target, metric, data) {\n var datapoints;\n if (!target.rate) {\n datapoints = _.map(data, point => [point.value, point.timestamp]);\n } else {\n var sortedData = data.sort((p1, p2)=> p1.timestamp - p2.timestamp);\n datapoints = _.chain(sortedData)\n .zip(sortedData.slice(1))\n .filter(pair => {\n return pair[1] // Exclude the last pair\n && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets\n })\n .map(pair => {\n var point1 = pair[0], point2 = pair[1];\n var timestamp = point2.timestamp;\n var value_diff = point2.value - point1.value;\n var time_diff = point2.timestamp - point1.timestamp;\n var rate = 60000 * value_diff / time_diff;\n return [rate, timestamp];\n })\n .value();\n }\n return {\n refId: target.refId,\n target: metric,\n datapoints: datapoints\n };\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/query_ctrl.js b/dist/query_ctrl.js
new file mode 100644
index 0000000..d87fdff
--- /dev/null
+++ b/dist/query_ctrl.js
@@ -0,0 +1,160 @@
+'use strict';
+
+System.register(['app/plugins/sdk', './css/query-editor.css!'], function (_export, _context) {
+ "use strict";
+
+ var QueryCtrl, _createClass, HawkularDatasourceQueryCtrl;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
+ return {
+ setters: [function (_appPluginsSdk) {
+ QueryCtrl = _appPluginsSdk.QueryCtrl;
+ }, function (_cssQueryEditorCss) {}],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('HawkularDatasourceQueryCtrl', HawkularDatasourceQueryCtrl = function (_QueryCtrl) {
+ _inherits(HawkularDatasourceQueryCtrl, _QueryCtrl);
+
+ function HawkularDatasourceQueryCtrl($scope, $injector, uiSegmentSrv, $q) {
+ _classCallCheck(this, HawkularDatasourceQueryCtrl);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(HawkularDatasourceQueryCtrl).call(this, $scope, $injector));
+
+ _this.scope = $scope;
+ _this.uiSegmentSrv = uiSegmentSrv;
+ _this.$q = $q;
+
+ _this.queryByTagCapability = false;
+ _this.datasource.getCapabilities().then(function (caps) {
+ _this.queryByTagCapability = caps.QUERY_BY_TAGS;
+ });
+
+ _this.listQueryBy = [{ value: 'ids', text: 'Search by name' }, { value: 'tags', text: 'Search by tags' }];
+ _this.metricTypes = [{ value: 'gauge', text: 'Gauge' }, { value: 'counter', text: 'Counter' }];
+
+ _this.target.queryBy = _this.target.queryBy || _this.listQueryBy[0].value;
+ _this.target.type = _this.target.type || _this.metricTypes[0].value;
+ _this.target.target = _this.target.target || 'select metric';
+ _this.target.rate = _this.target.rate === true;
+ _this.target.tags = _this.target.tags || [];
+
+ _this.tagsSegments = _.reduce(_this.target.tags, function (list, tag) {
+ list.push(uiSegmentSrv.newKey(tag.name));
+ list.push(uiSegmentSrv.newOperator(':'));
+ list.push(uiSegmentSrv.newKeyValue(tag.value));
+ list.push(uiSegmentSrv.newOperator(','));
+ return list;
+ }, []);
+ _this.tagsSegments.push(uiSegmentSrv.newPlusButton());
+ _this.removeTagsSegment = uiSegmentSrv.newSegment({ fake: true, value: '-- Remove tag --' });
+ return _this;
+ }
+
+ _createClass(HawkularDatasourceQueryCtrl, [{
+ key: 'getTagsSegments',
+ value: function getTagsSegments(segment, $index) {
+ if (segment.type === 'plus-button') {
+ return this.$q.when([]);
+ } else if (segment.type === 'key') {
+ return this.$q.when([angular.copy(this.removeTagsSegment)]);
+ } else if (segment.type === 'value') {
+ var key = this.tagsSegments[$index - 2].value;
+ return this.datasource.suggestTags(this.target.type, key).then(this.uiSegmentSrv.transformToSegments(false));
+ }
+ }
+ }, {
+ key: 'tagsSegmentChanged',
+ value: function tagsSegmentChanged(segment, index) {
+ if (segment.value === this.removeTagsSegment.value) {
+ this.tagsSegments.splice(index, 4);
+ } else if (segment.type === 'plus-button') {
+ this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));
+ this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());
+ } else {
+ this.tagsSegments[index] = segment;
+ }
+ this.tagsToModel();
+ this.onChangeInternal();
+ }
+ }, {
+ key: 'tagsToModel',
+ value: function tagsToModel() {
+ this.target.tags = [];
+ for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {
+ var key = this.tagsSegments[i].value;
+ var val = this.tagsSegments[i + 2].fake ? '*' : this.tagsSegments[i + 2].value || '*';
+ this.target.tags.push({ name: key, value: val });
+ }
+ }
+ }, {
+ key: 'getOptions',
+ value: function getOptions() {
+ return this.datasource.suggestQueries(this.target).then(this.uiSegmentSrv.transformToSegments(false));
+ // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive
+ }
+ }, {
+ key: 'onChangeInternal',
+ value: function onChangeInternal() {
+ this.panelCtrl.refresh(); // Asks the panel to refresh data.
+ }
+ }]);
+
+ return HawkularDatasourceQueryCtrl;
+ }(QueryCtrl));
+
+ _export('HawkularDatasourceQueryCtrl', HawkularDatasourceQueryCtrl);
+
+ HawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';
+ }
+ };
+});
+//# sourceMappingURL=query_ctrl.js.map
diff --git a/dist/query_ctrl.js.map b/dist/query_ctrl.js.map
new file mode 100644
index 0000000..ade2181
--- /dev/null
+++ b/dist/query_ctrl.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/query_ctrl.js"],"names":[],"mappings":"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","file":"query_ctrl.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport './css/query-editor.css!'\n\nexport class HawkularDatasourceQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector, uiSegmentSrv, $q) {\n super($scope, $injector);\n\n this.scope = $scope;\n this.uiSegmentSrv = uiSegmentSrv;\n this.$q = $q;\n\n this.queryByTagCapability = false;\n this.datasource.getCapabilities().then(caps => {\n this.queryByTagCapability = caps.QUERY_BY_TAGS;\n });\n\n this.listQueryBy = [\n {value: 'ids', text: 'Search by name'},\n {value: 'tags', text: 'Search by tags'}\n ];\n this.metricTypes = [\n {value: 'gauge', text: 'Gauge'},\n {value: 'counter', text: 'Counter'}\n ];\n\n this.target.queryBy = this.target.queryBy || this.listQueryBy[0].value;\n this.target.type = this.target.type || this.metricTypes[0].value;\n this.target.target = this.target.target || 'select metric';\n this.target.rate = this.target.rate === true;\n this.target.tags = this.target.tags || [];\n\n this.tagsSegments = _.reduce(this.target.tags, function(list, tag) {\n list.push(uiSegmentSrv.newKey(tag.name));\n list.push(uiSegmentSrv.newOperator(':'));\n list.push(uiSegmentSrv.newKeyValue(tag.value));\n list.push(uiSegmentSrv.newOperator(','));\n return list;\n }, []);\n this.tagsSegments.push(uiSegmentSrv.newPlusButton());\n this.removeTagsSegment = uiSegmentSrv.newSegment({fake: true, value: '-- Remove tag --'});\n }\n\n getTagsSegments(segment, $index) {\n if (segment.type === 'plus-button') {\n return this.$q.when([]);\n } else if (segment.type === 'key') {\n return this.$q.when([angular.copy(this.removeTagsSegment)]);\n } else if (segment.type === 'value') {\n var key = this.tagsSegments[$index-2].value;\n return this.datasource.suggestTags(this.target.type, key)\n .then(this.uiSegmentSrv.transformToSegments(false));\n }\n }\n\n tagsSegmentChanged(segment, index) {\n if (segment.value === this.removeTagsSegment.value) {\n this.tagsSegments.splice(index, 4);\n } else if (segment.type === 'plus-button') {\n this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));\n this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());\n } else {\n this.tagsSegments[index] = segment;\n }\n this.tagsToModel();\n this.onChangeInternal();\n }\n\n tagsToModel() {\n this.target.tags = [];\n for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {\n let key = this.tagsSegments[i].value;\n let val = this.tagsSegments[i+2].fake ? '*' : (this.tagsSegments[i+2].value || '*');\n this.target.tags.push({name: key, value: val});\n }\n }\n\n getOptions() {\n return this.datasource.suggestQueries(this.target)\n .then(this.uiSegmentSrv.transformToSegments(false));\n // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nHawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';\n"]}
\ No newline at end of file
diff --git a/dist/test/capabilities.js b/dist/test/capabilities.js
new file mode 100644
index 0000000..39e0641
--- /dev/null
+++ b/dist/test/capabilities.js
@@ -0,0 +1,27 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Capabilities = exports.Capabilities = function Capabilities(versionStr) {
+ _classCallCheck(this, Capabilities);
+
+ this.QUERY_POST_ENDPOINTS = true;
+ this.QUERY_BY_TAGS = true;
+ var regExp = new RegExp('([0-9]+)\.([0-9]+)\.(.+)');
+ if (versionStr.match(regExp)) {
+ var versionInfo = regExp.exec(versionStr);
+ var major = versionInfo[1];
+ var minor = versionInfo[2];
+ if (major == 0 && minor < 17) {
+ this.QUERY_POST_ENDPOINTS = false;
+ }
+ if (major == 0 && minor < 20) {
+ this.QUERY_BY_TAGS = false;
+ }
+ }
+};
+//# sourceMappingURL=capabilities.js.map
diff --git a/dist/test/capabilities.js.map b/dist/test/capabilities.js.map
new file mode 100644
index 0000000..2246731
--- /dev/null
+++ b/dist/test/capabilities.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/capabilities.js"],"names":[],"mappings":";;;;;;;;IAAa,Y,WAAA,Y,GAEX,sBAAY,UAAZ,EAAwB;AAAA;;AACtB,OAAK,oBAAL,GAA4B,IAA5B;AACA,OAAK,aAAL,GAAqB,IAArB;AACA,MAAI,SAAS,IAAI,MAAJ,CAAW,0BAAX,CAAb;AACA,MAAI,WAAW,KAAX,CAAiB,MAAjB,CAAJ,EAA8B;AAC5B,QAAI,cAAc,OAAO,IAAP,CAAY,UAAZ,CAAlB;AACA,QAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,QAAI,QAAQ,YAAY,CAAZ,CAAZ;AACA,QAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,WAAK,oBAAL,GAA4B,KAA5B;AACD;AACD,QAAI,SAAS,CAAT,IAAc,QAAQ,EAA1B,EAA8B;AAC5B,WAAK,aAAL,GAAqB,KAArB;AACD;AACF;AACF,C","file":"capabilities.js","sourcesContent":["export class Capabilities {\n\n constructor(versionStr) {\n this.QUERY_POST_ENDPOINTS = true;\n this.QUERY_BY_TAGS = true;\n let regExp = new RegExp('([0-9]+)\\.([0-9]+)\\.(.+)');\n if (versionStr.match(regExp)) {\n let versionInfo = regExp.exec(versionStr);\n let major = versionInfo[1];\n let minor = versionInfo[2];\n if (major == 0 && minor < 17) {\n this.QUERY_POST_ENDPOINTS = false;\n }\n if (major == 0 && minor < 20) {\n this.QUERY_BY_TAGS = false;\n }\n }\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/test/datasource.js b/dist/test/datasource.js
new file mode 100644
index 0000000..6ebe767
--- /dev/null
+++ b/dist/test/datasource.js
@@ -0,0 +1,202 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.HawkularDatasource = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _lodash = require('lodash');
+
+var _lodash2 = _interopRequireDefault(_lodash);
+
+var _variables = require('./variables');
+
+var _capabilities = require('./capabilities');
+
+var _queryProcessor = require('./queryProcessor');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var HawkularDatasource = exports.HawkularDatasource = function () {
+ function HawkularDatasource(instanceSettings, $q, backendSrv, templateSrv) {
+ _classCallCheck(this, HawkularDatasource);
+
+ this.type = instanceSettings.type;
+ this.url = instanceSettings.url;
+ this.name = instanceSettings.name;
+ this.tenant = instanceSettings.jsonData.tenant;
+ this.token = instanceSettings.jsonData.token;
+ this.q = $q;
+ this.backendSrv = backendSrv;
+ var variables = new _variables.Variables(templateSrv);
+ this.capabilitiesPromise = this.queryVersion().then(function (version) {
+ return new _capabilities.Capabilities(version);
+ });
+ this.queryProcessor = new _queryProcessor.QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());
+ }
+
+ _createClass(HawkularDatasource, [{
+ key: 'query',
+ value: function query(options) {
+ var _this = this;
+
+ var validTargets = options.targets.filter(function (target) {
+ return !target.hide;
+ }).filter(function (target) {
+ return target.target !== 'select metric';
+ });
+
+ if (validTargets.length === 0) {
+ return this.q.when({ data: [] });
+ }
+
+ var promises = validTargets.map(function (target) {
+ return _this.queryProcessor.run(target, options);
+ });
+
+ return this.q.all(promises).then(function (responses) {
+ var flatten = [].concat.apply([], responses);
+ return { data: flatten };
+ });
+ }
+ }, {
+ key: 'createHeaders',
+ value: function createHeaders() {
+ var headers = {
+ 'Content-Type': 'application/json',
+ 'Hawkular-Tenant': this.tenant
+ };
+ if (typeof this.token === 'string' && this.token.length > 0) {
+ headers.Authorization = 'Bearer ' + this.token;
+ }
+ return headers;
+ }
+ }, {
+ key: 'testDatasource',
+ value: function testDatasource() {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/status',
+ method: 'GET'
+ }).then(function (response) {
+ if (response.status === 200) {
+ return { status: "success", message: "Data source is working", title: "Success" };
+ }
+ });
+ }
+ }, {
+ key: 'annotationQuery',
+ value: function annotationQuery(options) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/annotations',
+ method: 'POST',
+ data: options
+ }).then(function (result) {
+ return result.data;
+ });
+ }
+ }, {
+ key: 'suggestQueries',
+ value: function suggestQueries(target) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics?type=' + target.type,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ return _lodash2.default.map(result.data, function (metric) {
+ return { text: metric.id, value: metric.id };
+ });
+ });
+ }
+ }, {
+ key: 'suggestTags',
+ value: function suggestTags(type, key) {
+ if (!key) {
+ // Need at least some characters typed in order to suggest something
+ return this.q.when([]);
+ }
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/' + type + 's/tags/' + key + ':*',
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ if (result.data.hasOwnProperty(key)) {
+ return [' *'].concat(result.data[key]).map(function (value) {
+ return { text: value, value: value };
+ });
+ }
+ return [];
+ });
+ }
+ }, {
+ key: 'metricFindQuery',
+ value: function metricFindQuery(query) {
+ var params = "";
+ if (query !== undefined) {
+ if (query.startsWith("tags/")) {
+ return this.findTags(query.substr(5).trim());
+ }
+ if (query.startsWith("?")) {
+ params = query;
+ } else {
+ params = "?" + query;
+ }
+ }
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics' + params,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ return _lodash2.default.map(result.data, function (metric) {
+ return { text: metric.id, value: metric.id };
+ });
+ });
+ }
+ }, {
+ key: 'findTags',
+ value: function findTags(pattern) {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/metrics/tags/' + pattern,
+ method: 'GET',
+ headers: this.createHeaders()
+ }).then(function (result) {
+ var flatTags = [];
+ if (result.data) {
+ var data = result.data;
+ for (var property in data) {
+ if (data.hasOwnProperty(property)) {
+ flatTags = flatTags.concat(data[property]);
+ }
+ }
+ }
+ return flatTags.map(function (tag) {
+ return { text: tag, value: tag };
+ });
+ });
+ }
+ }, {
+ key: 'queryVersion',
+ value: function queryVersion() {
+ return this.backendSrv.datasourceRequest({
+ url: this.url + '/status',
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function (response) {
+ return response.data['Implementation-Version'];
+ }).catch(function (response) {
+ return "Unknown";
+ });
+ }
+ }, {
+ key: 'getCapabilities',
+ value: function getCapabilities() {
+ return this.capabilitiesPromise;
+ }
+ }]);
+
+ return HawkularDatasource;
+}();
+//# sourceMappingURL=datasource.js.map
diff --git a/dist/test/datasource.js.map b/dist/test/datasource.js.map
new file mode 100644
index 0000000..c0f4811
--- /dev/null
+++ b/dist/test/datasource.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/datasource.js"],"names":[],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\nimport {Variables} from './variables';\nimport {Capabilities} from './capabilities';\nimport {QueryProcessor} from './queryProcessor';\n\nexport class HawkularDatasource {\n\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.type = instanceSettings.type;\n this.url = instanceSettings.url;\n this.name = instanceSettings.name;\n this.tenant = instanceSettings.jsonData.tenant;\n this.token = instanceSettings.jsonData.token;\n this.q = $q;\n this.backendSrv = backendSrv;\n let variables = new Variables(templateSrv);\n this.capabilitiesPromise = this.queryVersion()\n .then(version => new Capabilities(version));\n this.queryProcessor = new QueryProcessor($q, backendSrv, variables, this.capabilitiesPromise, this.url, this.createHeaders());\n }\n\n query(options) {\n let validTargets = options.targets\n .filter(target => !target.hide)\n .filter(target => target.target !== 'select metric');\n\n if (validTargets.length === 0) {\n return this.q.when({data: []});\n }\n\n let promises = validTargets.map(target => {\n return this.queryProcessor.run(target, options);\n });\n\n return this.q.all(promises).then(responses => {\n let flatten = [].concat.apply([], responses);\n return {data: flatten};\n });\n }\n\n createHeaders() {\n var headers = {\n 'Content-Type': 'application/json',\n 'Hawkular-Tenant': this.tenant\n };\n if (typeof this.token === 'string' && this.token.length > 0) {\n headers.Authorization = 'Bearer ' + this.token;\n }\n return headers;\n }\n\n testDatasource() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET'\n }).then(response => {\n if (response.status === 200) {\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\n }\n });\n }\n\n annotationQuery(options) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/annotations',\n method: 'POST',\n data: options\n }).then(result => {\n return result.data;\n });\n }\n\n suggestQueries(target) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics?type=' + target.type,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n suggestTags(type, key) {\n if (!key) {\n // Need at least some characters typed in order to suggest something\n return this.q.when([]);\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/' + type + 's/tags/' + key + ':*',\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n if (result.data.hasOwnProperty(key)) {\n return [' *'].concat(result.data[key]).map(value => {\n return {text: value, value: value};\n });\n }\n return [];\n });\n }\n\n metricFindQuery(query) {\n var params = \"\";\n if (query !== undefined) {\n if (query.startsWith(\"tags/\")) {\n return this.findTags(query.substr(5).trim());\n }\n if (query.startsWith(\"?\")) {\n params = query;\n } else {\n params = \"?\" + query;\n }\n }\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics' + params,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n return _.map(result.data, metric => {\n return {text: metric.id, value: metric.id};\n });\n });\n }\n\n findTags(pattern) {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/metrics/tags/' + pattern,\n method: 'GET',\n headers: this.createHeaders()\n }).then(result => {\n var flatTags = [];\n if (result.data) {\n var data = result.data;\n for (var property in data) {\n if (data.hasOwnProperty(property)) {\n flatTags = flatTags.concat(data[property]);\n }\n }\n }\n return flatTags.map(tag => {\n return {text: tag, value: tag};\n });\n });\n }\n\n queryVersion() {\n return this.backendSrv.datasourceRequest({\n url: this.url + '/status',\n method: 'GET',\n headers: {'Content-Type': 'application/json'}\n }).then(response => response.data['Implementation-Version'])\n .catch(response => \"Unknown\");\n }\n\n getCapabilities() {\n return this.capabilitiesPromise;\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/test/module.js b/dist/test/module.js
new file mode 100644
index 0000000..e91c7cb
--- /dev/null
+++ b/dist/test/module.js
@@ -0,0 +1,37 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.AnnotationsQueryCtrl = exports.QueryOptionsCtrl = exports.ConfigCtrl = exports.QueryCtrl = exports.Datasource = undefined;
+
+var _datasource = require('./datasource');
+
+var _query_ctrl = require('./query_ctrl');
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var HawkularConfigCtrl = function HawkularConfigCtrl() {
+ _classCallCheck(this, HawkularConfigCtrl);
+};
+
+HawkularConfigCtrl.templateUrl = 'partials/config.html';
+
+var HawkularQueryOptionsCtrl = function HawkularQueryOptionsCtrl() {
+ _classCallCheck(this, HawkularQueryOptionsCtrl);
+};
+
+HawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';
+
+var HawkularAnnotationsQueryCtrl = function HawkularAnnotationsQueryCtrl() {
+ _classCallCheck(this, HawkularAnnotationsQueryCtrl);
+};
+
+HawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';
+
+exports.Datasource = _datasource.HawkularDatasource;
+exports.QueryCtrl = _query_ctrl.HawkularDatasourceQueryCtrl;
+exports.ConfigCtrl = HawkularConfigCtrl;
+exports.QueryOptionsCtrl = HawkularQueryOptionsCtrl;
+exports.AnnotationsQueryCtrl = HawkularAnnotationsQueryCtrl;
+//# sourceMappingURL=module.js.map
diff --git a/dist/test/module.js.map b/dist/test/module.js.map
new file mode 100644
index 0000000..b2ee928
--- /dev/null
+++ b/dist/test/module.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/module.js"],"names":[],"mappings":";;;;;;;AAAA;;AACA;;;;IAEM,kB;;;;AACN,mBAAmB,WAAnB,GAAiC,sBAAjC;;IAEM,wB;;;;AACN,yBAAyB,WAAzB,GAAuC,6BAAvC;;IAEM,4B;;;;AACN,6BAA6B,WAA7B,GAA2C,kCAA3C;;QAGwB,U;QACS,S;QACT,U,GAAtB,kB;QAC4B,gB,GAA5B,wB;QACgC,oB,GAAhC,4B","file":"module.js","sourcesContent":["import {HawkularDatasource} from './datasource';\nimport {HawkularDatasourceQueryCtrl} from './query_ctrl';\n\nclass HawkularConfigCtrl {}\nHawkularConfigCtrl.templateUrl = 'partials/config.html';\n\nclass HawkularQueryOptionsCtrl {}\nHawkularQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\n\nclass HawkularAnnotationsQueryCtrl {}\nHawkularAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html';\n\nexport {\n HawkularDatasource as Datasource,\n HawkularDatasourceQueryCtrl as QueryCtrl,\n HawkularConfigCtrl as ConfigCtrl,\n HawkularQueryOptionsCtrl as QueryOptionsCtrl,\n HawkularAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]}
\ No newline at end of file
diff --git a/dist/test/queryProcessor.js b/dist/test/queryProcessor.js
new file mode 100644
index 0000000..f0e8221
--- /dev/null
+++ b/dist/test/queryProcessor.js
@@ -0,0 +1,181 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var QueryProcessor = exports.QueryProcessor = function () {
+ function QueryProcessor(q, backendSrv, variables, capabilities, url, baseHeaders) {
+ _classCallCheck(this, QueryProcessor);
+
+ this.q = q;
+ this.backendSrv = backendSrv;
+ this.variables = variables;
+ this.capabilities = capabilities;
+ this.url = url;
+ this.baseHeaders = baseHeaders;
+ }
+
+ _createClass(QueryProcessor, [{
+ key: 'run',
+ value: function run(target, options) {
+ var _this = this;
+
+ return this.capabilities.then(function (caps) {
+ if (target.queryBy === 'ids') {
+ var metricIds = _this.variables.resolve(target.target, options);
+ if (caps.QUERY_POST_ENDPOINTS) {
+ return _this.rawQuery(target, options.range, metricIds);
+ } else {
+ return _this.rawQueryLegacy(target, options.range, metricIds);
+ }
+ } else {
+ if (target.tags.length === 0) {
+ return _this.q.when([]);
+ }
+ var strTags = _this.hawkularFormatTags(target.tags, options);
+ return _this.rawQueryByTags(target, options.range, strTags);
+ }
+ });
+ }
+ }, {
+ key: 'hawkularFormatTags',
+ value: function hawkularFormatTags(tags, options) {
+ var _this2 = this;
+
+ return tags.map(function (tag) {
+ var value;
+ if (tag.value === ' *') {
+ // '*' character get a special treatment in grafana so we had to use ' *' instead
+ value = '*';
+ } else {
+ value = _this2.variables.resolve(tag.value, options).join('|');
+ }
+ return tag.name + ':' + value;
+ }).join(',');
+ }
+ }, {
+ key: 'rawQuery',
+ value: function rawQuery(target, range, metricIds) {
+ var _this3 = this;
+
+ var uri = [target.type + 's', // gauges or counters
+ target.rate ? 'rate' : 'raw', // raw or rate
+ 'query'];
+ var url = this.url + '/' + uri.join('/');
+
+ return this.backendSrv.datasourceRequest({
+ url: url,
+ data: {
+ ids: metricIds,
+ start: range.from.valueOf(),
+ end: range.to.valueOf(),
+ order: 'ASC'
+ },
+ method: 'POST',
+ headers: this.baseHeaders
+ }).then(function (response) {
+ return _this3.processRawResponse(target, response.status == 200 ? response.data : []);
+ });
+ }
+ }, {
+ key: 'rawQueryLegacy',
+ value: function rawQueryLegacy(target, range, metricIds) {
+ var _this4 = this;
+
+ return this.q.all(metricIds.map(function (metric) {
+ var uri = [target.type + 's', // gauges or counters
+ encodeURIComponent(metric).replace('+', '%20'), // metric name
+ 'data'];
+ var url = _this4.url + '/' + uri.join('/');
+
+ return _this4.backendSrv.datasourceRequest({
+ url: url,
+ params: {
+ start: range.from.valueOf(),
+ end: range.to.valueOf()
+ },
+ method: 'GET',
+ headers: _this4.baseHeaders
+ }).then(function (response) {
+ return _this4.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []);
+ });
+ }));
+ }
+ }, {
+ key: 'rawQueryByTags',
+ value: function rawQueryByTags(target, range, tags) {
+ var _this5 = this;
+
+ var uri = [target.type + 's', // gauges or counters
+ target.rate ? 'rate' : 'raw', // raw or rate
+ 'query'];
+ var url = this.url + '/' + uri.join('/');
+
+ return this.backendSrv.datasourceRequest({
+ url: url,
+ data: {
+ tags: tags,
+ start: range.from.valueOf(),
+ end: range.to.valueOf(),
+ order: 'ASC'
+ },
+ method: 'POST',
+ headers: this.baseHeaders
+ }).then(function (response) {
+ return _this5.processRawResponse(target, response.status == 200 ? response.data : []);
+ });
+ }
+ }, {
+ key: 'processRawResponse',
+ value: function processRawResponse(target, data) {
+ return data.map(function (timeSerie) {
+ return {
+ refId: target.refId,
+ target: timeSerie.id,
+ datapoints: timeSerie.data.map(function (point) {
+ return [point.value, point.timestamp];
+ })
+ };
+ });
+ }
+ }, {
+ key: 'processRawResponseLegacy',
+ value: function processRawResponseLegacy(target, metric, data) {
+ var datapoints;
+ if (!target.rate) {
+ datapoints = _.map(data, function (point) {
+ return [point.value, point.timestamp];
+ });
+ } else {
+ var sortedData = data.sort(function (p1, p2) {
+ return p1.timestamp - p2.timestamp;
+ });
+ datapoints = _.chain(sortedData).zip(sortedData.slice(1)).filter(function (pair) {
+ return pair[1] // Exclude the last pair
+ && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets
+ }).map(function (pair) {
+ var point1 = pair[0],
+ point2 = pair[1];
+ var timestamp = point2.timestamp;
+ var value_diff = point2.value - point1.value;
+ var time_diff = point2.timestamp - point1.timestamp;
+ var rate = 60000 * value_diff / time_diff;
+ return [rate, timestamp];
+ }).value();
+ }
+ return {
+ refId: target.refId,
+ target: metric,
+ datapoints: datapoints
+ };
+ }
+ }]);
+
+ return QueryProcessor;
+}();
+//# sourceMappingURL=queryProcessor.js.map
diff --git a/dist/test/queryProcessor.js.map b/dist/test/queryProcessor.js.map
new file mode 100644
index 0000000..ad6e97f
--- /dev/null
+++ b/dist/test/queryProcessor.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/queryProcessor.js"],"names":[],"mappings":"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","file":"queryProcessor.js","sourcesContent":["export class QueryProcessor {\n\n constructor(q, backendSrv, variables, capabilities, url, baseHeaders) {\n this.q = q;\n this.backendSrv = backendSrv;\n this.variables = variables;\n this.capabilities = capabilities;\n this.url = url;\n this.baseHeaders = baseHeaders;\n }\n\n run(target, options) {\n return this.capabilities.then(caps => {\n if (target.queryBy === 'ids') {\n let metricIds = this.variables.resolve(target.target, options);\n if (caps.QUERY_POST_ENDPOINTS) {\n return this.rawQuery(target, options.range, metricIds);\n } else {\n return this.rawQueryLegacy(target, options.range, metricIds);\n }\n } else {\n if (target.tags.length === 0) {\n return this.q.when([]);\n }\n let strTags = this.hawkularFormatTags(target.tags, options);\n return this.rawQueryByTags(target, options.range, strTags);\n }\n });\n }\n\n hawkularFormatTags(tags, options) {\n return tags.map(tag => {\n var value;\n if (tag.value === ' *') {\n // '*' character get a special treatment in grafana so we had to use ' *' instead\n value = '*';\n } else {\n value = this.variables.resolve(tag.value, options).join('|');\n }\n return tag.name + ':' + value;\n }).join(',');\n }\n\n rawQuery(target, range, metricIds) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n ids: metricIds,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n rawQueryLegacy(target, range, metricIds) {\n return this.q.all(metricIds.map(metric => {\n let uri = [\n target.type + 's', // gauges or counters\n encodeURIComponent(metric).replace('+', '%20'), // metric name\n 'data'];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n params: {\n start: range.from.valueOf(),\n end: range.to.valueOf()\n },\n method: 'GET',\n headers: this.baseHeaders\n }).then(response => this.processRawResponseLegacy(target, metric, response.status == 200 ? response.data : []));\n }));\n }\n\n rawQueryByTags(target, range, tags) {\n let uri = [\n target.type + 's', // gauges or counters\n target.rate ? 'rate' : 'raw', // raw or rate\n 'query'\n ];\n let url = this.url + '/' + uri.join('/');\n\n return this.backendSrv.datasourceRequest({\n url: url,\n data: {\n tags: tags,\n start: range.from.valueOf(),\n end: range.to.valueOf(),\n order: 'ASC'\n },\n method: 'POST',\n headers: this.baseHeaders\n }).then(response => this.processRawResponse(target, response.status == 200 ? response.data : []));\n }\n\n processRawResponse(target, data) {\n return data.map(timeSerie => {\n return {\n refId: target.refId,\n target: timeSerie.id,\n datapoints: timeSerie.data.map(point => [point.value, point.timestamp])\n };\n });\n }\n\n processRawResponseLegacy(target, metric, data) {\n var datapoints;\n if (!target.rate) {\n datapoints = _.map(data, point => [point.value, point.timestamp]);\n } else {\n var sortedData = data.sort((p1, p2)=> p1.timestamp - p2.timestamp);\n datapoints = _.chain(sortedData)\n .zip(sortedData.slice(1))\n .filter(pair => {\n return pair[1] // Exclude the last pair\n && (target.type == 'gauge' || pair[0].value <= pair[1].value); // Exclude counter resets\n })\n .map(pair => {\n var point1 = pair[0], point2 = pair[1];\n var timestamp = point2.timestamp;\n var value_diff = point2.value - point1.value;\n var time_diff = point2.timestamp - point1.timestamp;\n var rate = 60000 * value_diff / time_diff;\n return [rate, timestamp];\n })\n .value();\n }\n return {\n refId: target.refId,\n target: metric,\n datapoints: datapoints\n };\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/test/query_ctrl.js b/dist/test/query_ctrl.js
new file mode 100644
index 0000000..ca27a30
--- /dev/null
+++ b/dist/test/query_ctrl.js
@@ -0,0 +1,114 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.HawkularDatasourceQueryCtrl = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _sdk = require('app/plugins/sdk');
+
+require('./css/query-editor.css!');
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var HawkularDatasourceQueryCtrl = exports.HawkularDatasourceQueryCtrl = function (_QueryCtrl) {
+ _inherits(HawkularDatasourceQueryCtrl, _QueryCtrl);
+
+ function HawkularDatasourceQueryCtrl($scope, $injector, uiSegmentSrv, $q) {
+ _classCallCheck(this, HawkularDatasourceQueryCtrl);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(HawkularDatasourceQueryCtrl).call(this, $scope, $injector));
+
+ _this.scope = $scope;
+ _this.uiSegmentSrv = uiSegmentSrv;
+ _this.$q = $q;
+
+ _this.queryByTagCapability = false;
+ _this.datasource.getCapabilities().then(function (caps) {
+ _this.queryByTagCapability = caps.QUERY_BY_TAGS;
+ });
+
+ _this.listQueryBy = [{ value: 'ids', text: 'Search by name' }, { value: 'tags', text: 'Search by tags' }];
+ _this.metricTypes = [{ value: 'gauge', text: 'Gauge' }, { value: 'counter', text: 'Counter' }];
+
+ _this.target.queryBy = _this.target.queryBy || _this.listQueryBy[0].value;
+ _this.target.type = _this.target.type || _this.metricTypes[0].value;
+ _this.target.target = _this.target.target || 'select metric';
+ _this.target.rate = _this.target.rate === true;
+ _this.target.tags = _this.target.tags || [];
+
+ _this.tagsSegments = _.reduce(_this.target.tags, function (list, tag) {
+ list.push(uiSegmentSrv.newKey(tag.name));
+ list.push(uiSegmentSrv.newOperator(':'));
+ list.push(uiSegmentSrv.newKeyValue(tag.value));
+ list.push(uiSegmentSrv.newOperator(','));
+ return list;
+ }, []);
+ _this.tagsSegments.push(uiSegmentSrv.newPlusButton());
+ _this.removeTagsSegment = uiSegmentSrv.newSegment({ fake: true, value: '-- Remove tag --' });
+ return _this;
+ }
+
+ _createClass(HawkularDatasourceQueryCtrl, [{
+ key: 'getTagsSegments',
+ value: function getTagsSegments(segment, $index) {
+ if (segment.type === 'plus-button') {
+ return this.$q.when([]);
+ } else if (segment.type === 'key') {
+ return this.$q.when([angular.copy(this.removeTagsSegment)]);
+ } else if (segment.type === 'value') {
+ var key = this.tagsSegments[$index - 2].value;
+ return this.datasource.suggestTags(this.target.type, key).then(this.uiSegmentSrv.transformToSegments(false));
+ }
+ }
+ }, {
+ key: 'tagsSegmentChanged',
+ value: function tagsSegmentChanged(segment, index) {
+ if (segment.value === this.removeTagsSegment.value) {
+ this.tagsSegments.splice(index, 4);
+ } else if (segment.type === 'plus-button') {
+ this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));
+ this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));
+ this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());
+ } else {
+ this.tagsSegments[index] = segment;
+ }
+ this.tagsToModel();
+ this.onChangeInternal();
+ }
+ }, {
+ key: 'tagsToModel',
+ value: function tagsToModel() {
+ this.target.tags = [];
+ for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {
+ var key = this.tagsSegments[i].value;
+ var val = this.tagsSegments[i + 2].fake ? '*' : this.tagsSegments[i + 2].value || '*';
+ this.target.tags.push({ name: key, value: val });
+ }
+ }
+ }, {
+ key: 'getOptions',
+ value: function getOptions() {
+ return this.datasource.suggestQueries(this.target).then(this.uiSegmentSrv.transformToSegments(false));
+ // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive
+ }
+ }, {
+ key: 'onChangeInternal',
+ value: function onChangeInternal() {
+ this.panelCtrl.refresh(); // Asks the panel to refresh data.
+ }
+ }]);
+
+ return HawkularDatasourceQueryCtrl;
+}(_sdk.QueryCtrl);
+
+HawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';
+//# sourceMappingURL=query_ctrl.js.map
diff --git a/dist/test/query_ctrl.js.map b/dist/test/query_ctrl.js.map
new file mode 100644
index 0000000..d4e04fc
--- /dev/null
+++ b/dist/test/query_ctrl.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/query_ctrl.js"],"names":[],"mappings":"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","file":"query_ctrl.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport './css/query-editor.css!'\n\nexport class HawkularDatasourceQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector, uiSegmentSrv, $q) {\n super($scope, $injector);\n\n this.scope = $scope;\n this.uiSegmentSrv = uiSegmentSrv;\n this.$q = $q;\n\n this.queryByTagCapability = false;\n this.datasource.getCapabilities().then(caps => {\n this.queryByTagCapability = caps.QUERY_BY_TAGS;\n });\n\n this.listQueryBy = [\n {value: 'ids', text: 'Search by name'},\n {value: 'tags', text: 'Search by tags'}\n ];\n this.metricTypes = [\n {value: 'gauge', text: 'Gauge'},\n {value: 'counter', text: 'Counter'}\n ];\n\n this.target.queryBy = this.target.queryBy || this.listQueryBy[0].value;\n this.target.type = this.target.type || this.metricTypes[0].value;\n this.target.target = this.target.target || 'select metric';\n this.target.rate = this.target.rate === true;\n this.target.tags = this.target.tags || [];\n\n this.tagsSegments = _.reduce(this.target.tags, function(list, tag) {\n list.push(uiSegmentSrv.newKey(tag.name));\n list.push(uiSegmentSrv.newOperator(':'));\n list.push(uiSegmentSrv.newKeyValue(tag.value));\n list.push(uiSegmentSrv.newOperator(','));\n return list;\n }, []);\n this.tagsSegments.push(uiSegmentSrv.newPlusButton());\n this.removeTagsSegment = uiSegmentSrv.newSegment({fake: true, value: '-- Remove tag --'});\n }\n\n getTagsSegments(segment, $index) {\n if (segment.type === 'plus-button') {\n return this.$q.when([]);\n } else if (segment.type === 'key') {\n return this.$q.when([angular.copy(this.removeTagsSegment)]);\n } else if (segment.type === 'value') {\n var key = this.tagsSegments[$index-2].value;\n return this.datasource.suggestTags(this.target.type, key)\n .then(this.uiSegmentSrv.transformToSegments(false));\n }\n }\n\n tagsSegmentChanged(segment, index) {\n if (segment.value === this.removeTagsSegment.value) {\n this.tagsSegments.splice(index, 4);\n } else if (segment.type === 'plus-button') {\n this.tagsSegments.splice(index, 1, this.uiSegmentSrv.newOperator(','));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKeyValue(' *'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newOperator(':'));\n this.tagsSegments.splice(index, 0, this.uiSegmentSrv.newKey(segment.value));\n this.tagsSegments.push(this.uiSegmentSrv.newPlusButton());\n } else {\n this.tagsSegments[index] = segment;\n }\n this.tagsToModel();\n this.onChangeInternal();\n }\n\n tagsToModel() {\n this.target.tags = [];\n for (var i = 0; i < this.tagsSegments.length - 2; i += 4) {\n let key = this.tagsSegments[i].value;\n let val = this.tagsSegments[i+2].fake ? '*' : (this.tagsSegments[i+2].value || '*');\n this.target.tags.push({name: key, value: val});\n }\n }\n\n getOptions() {\n return this.datasource.suggestQueries(this.target)\n .then(this.uiSegmentSrv.transformToSegments(false));\n // Options have to be transformed by uiSegmentSrv to be usable by metric-segment-model directive\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nHawkularDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';\n"]}
\ No newline at end of file
diff --git a/dist/test/spec/datasource_spec.js b/dist/test/spec/datasource_spec.js
new file mode 100644
index 0000000..7bf71fc
--- /dev/null
+++ b/dist/test/spec/datasource_spec.js
@@ -0,0 +1,200 @@
+"use strict";
+
+var _module = require("../module");
+
+var _q = require("q");
+
+var _q2 = _interopRequireDefault(_q);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+describe('HawkularDatasource', function () {
+ var ctx = {};
+ var hProtocol = 'https';
+ var hHostname = 'test.com';
+ var hPort = '876';
+ var hPath = 'hawkular/metrics';
+ var instanceSettings = {
+ url: hProtocol + '://' + hHostname + ':' + hPort + '/' + hPath,
+ jsonData: {
+ tenant: 'test-tenant'
+ }
+ };
+
+ var parsePathElements = function parsePathElements(request) {
+ expect(request.method).to.equal('POST');
+ expect(request.headers).to.have.property('Hawkular-Tenant', instanceSettings.jsonData.tenant);
+
+ var parser = document.createElement('a');
+ parser.href = request.url;
+
+ expect(parser).to.have.property('protocol', hProtocol + ':');
+ expect(parser).to.have.property('hostname', hHostname);
+ expect(parser).to.have.property('port', hPort);
+ expect(parser).to.have.property('pathname');
+
+ return parser.pathname.split('/').filter(function (e) {
+ return e.length != 0;
+ });
+ };
+
+ beforeEach(function () {
+ ctx.$q = _q2.default;
+ ctx.backendSrv = {};
+ ctx.backendSrv.datasourceRequest = function (request) {
+ return ctx.$q.when({ data: { 'Implementation-Version': '1.0.0' } });
+ };
+ ctx.templateSrv = {
+ replace: function replace(target, vars) {
+ return target;
+ }
+ };
+ ctx.ds = new _module.Datasource(instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv);
+ });
+
+ it('should return an empty array when no targets are set', function (done) {
+ ctx.ds.query({ targets: [] }).then(function (result) {
+ expect(result).to.have.property('data').with.length(0);
+ }).then(function (v) {
+ return done();
+ }, function (err) {
+ return done(err);
+ });
+ });
+
+ it('should return the server results when a target is set', function (done) {
+
+ var options = {
+ range: {
+ from: 15,
+ to: 30
+ },
+ targets: [{
+ target: 'memory',
+ type: 'gauge',
+ rate: false,
+ queryBy: 'ids'
+ }, {
+ target: 'packets',
+ type: 'counter',
+ rate: true,
+ queryBy: 'ids'
+ }]
+ };
+
+ ctx.backendSrv.datasourceRequest = function (request) {
+ var pathElements = parsePathElements(request);
+ var id = pathElements[2] == 'gauges' ? 'memory' : 'packets';
+
+ expect(pathElements).to.have.length(5);
+ expect(pathElements.slice(0, 2)).to.deep.equal(hPath.split('/'));
+ expect(pathElements[2]).to.be.oneOf(['gauges', 'counters']);
+ if (pathElements[2] == 'gauges') {
+ expect(pathElements.slice(3)).to.deep.equal(['raw', 'query']);
+ expect(request.data).to.deep.equal({
+ start: options.range.from,
+ end: options.range.to,
+ ids: [id],
+ order: 'ASC'
+ });
+ } else {
+ expect(pathElements.slice(3)).to.deep.equal(['rate', 'query']);
+ expect(request.data).to.deep.equal({
+ start: options.range.from,
+ end: options.range.to,
+ ids: [id],
+ order: 'ASC'
+ });
+ }
+
+ return ctx.$q.when({
+ status: 200,
+ data: [{
+ id: id,
+ data: [{
+ timestamp: 13,
+ value: 15
+ }, {
+ timestamp: 19,
+ value: 21
+ }]
+ }]
+ });
+ };
+
+ ctx.ds.query(options).then(function (result) {
+ expect(result.data).to.have.length(2);
+ expect(result.data.map(function (t) {
+ return t.target;
+ })).to.include.members(['memory', 'packets']);
+ expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);
+ expect(result.data[1].datapoints).to.deep.equal([[15, 13], [21, 19]]);
+ }).then(function (v) {
+ return done();
+ }, function (err) {
+ return done(err);
+ });
+ });
+
+ it('should return multiple results with templated target', function (done) {
+
+ var options = {
+ range: {
+ from: 15,
+ to: 30
+ },
+ targets: [{
+ target: '$app/memory',
+ type: 'gauge',
+ rate: false,
+ queryBy: 'ids'
+ }]
+ };
+
+ ctx.templateSrv.replace = function (target, vars) {
+ expect(target).to.equal('$app');
+ return "{app_1,app_2}";
+ };
+
+ ctx.backendSrv.datasourceRequest = function (request) {
+ expect(request.url).to.have.string("/gauges/raw/query");
+ expect(request.data.ids).to.include.members(['app_1/memory', 'app_2/memory']);
+ return ctx.$q.when({
+ status: 200,
+ data: [{
+ id: "app_1/memory",
+ data: [{
+ timestamp: 13,
+ value: 15
+ }, {
+ timestamp: 19,
+ value: 21
+ }]
+ }, {
+ id: "app_2/memory",
+ data: [{
+ timestamp: 13,
+ value: 28
+ }, {
+ timestamp: 19,
+ value: 32
+ }]
+ }]
+ });
+ };
+
+ ctx.ds.query(options).then(function (result) {
+ expect(result.data).to.have.length(2);
+ expect(result.data.map(function (t) {
+ return t.target;
+ })).to.include.members(['app_1/memory', 'app_2/memory']);
+ expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);
+ expect(result.data[1].datapoints).to.deep.equal([[28, 13], [32, 19]]);
+ }).then(function (v) {
+ return done();
+ }, function (err) {
+ return done(err);
+ });
+ });
+});
+//# sourceMappingURL=datasource_spec.js.map
diff --git a/dist/test/spec/datasource_spec.js.map b/dist/test/spec/datasource_spec.js.map
new file mode 100644
index 0000000..91e524c
--- /dev/null
+++ b/dist/test/spec/datasource_spec.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../../spec/datasource_spec.js"],"names":[],"mappings":"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","file":"datasource_spec.js","sourcesContent":["import {Datasource} from \"../module\";\nimport Q from \"q\";\n\ndescribe('HawkularDatasource', function () {\n var ctx = {};\n var hProtocol = 'https';\n var hHostname = 'test.com';\n var hPort = '876';\n var hPath = 'hawkular/metrics';\n var instanceSettings = {\n url: hProtocol + '://' + hHostname + ':' + hPort + '/' + hPath,\n jsonData: {\n tenant: 'test-tenant'\n }\n };\n\n var parsePathElements = function(request) {\n expect(request.method).to.equal('POST');\n expect(request.headers).to.have.property('Hawkular-Tenant', instanceSettings.jsonData.tenant);\n\n var parser = document.createElement('a');\n parser.href = request.url;\n\n expect(parser).to.have.property('protocol', hProtocol + ':');\n expect(parser).to.have.property('hostname', hHostname);\n expect(parser).to.have.property('port', hPort);\n expect(parser).to.have.property('pathname');\n\n return parser.pathname.split('/').filter(e => e.length != 0);\n }\n\n beforeEach(function () {\n ctx.$q = Q;\n ctx.backendSrv = {};\n ctx.backendSrv.datasourceRequest = function (request) {\n return ctx.$q.when({data: {'Implementation-Version': '1.0.0'}})\n };\n ctx.templateSrv = {\n replace: function(target, vars) {\n return target;\n }\n };\n ctx.ds = new Datasource(instanceSettings, ctx.$q, ctx.backendSrv, ctx.templateSrv);\n });\n\n it('should return an empty array when no targets are set', function (done) {\n ctx.ds.query({targets: []}).then(function (result) {\n expect(result).to.have.property('data').with.length(0);\n }).then(v => done(), err => done(err));\n });\n\n it('should return the server results when a target is set', function (done) {\n\n var options = {\n range: {\n from: 15,\n to: 30\n },\n targets: [{\n target: 'memory',\n type: 'gauge',\n rate: false,\n queryBy: 'ids'\n }, {\n target: 'packets',\n type: 'counter',\n rate: true,\n queryBy: 'ids'\n }]\n };\n\n ctx.backendSrv.datasourceRequest = function (request) {\n let pathElements = parsePathElements(request);\n var id = pathElements[2] == 'gauges' ? 'memory' : 'packets';\n\n expect(pathElements).to.have.length(5);\n expect(pathElements.slice(0, 2)).to.deep.equal(hPath.split('/'));\n expect(pathElements[2]).to.be.oneOf(['gauges', 'counters']);\n if (pathElements[2] == 'gauges') {\n expect(pathElements.slice(3)).to.deep.equal(['raw', 'query']);\n expect(request.data).to.deep.equal({\n start: options.range.from,\n end: options.range.to,\n ids: [id],\n order: 'ASC'\n });\n } else {\n expect(pathElements.slice(3)).to.deep.equal(['rate', 'query']);\n expect(request.data).to.deep.equal({\n start: options.range.from,\n end: options.range.to,\n ids: [id],\n order: 'ASC'\n });\n }\n\n return ctx.$q.when({\n status: 200,\n data: [{\n id: id,\n data: [{\n timestamp: 13,\n value: 15\n }, {\n timestamp: 19,\n value: 21\n }]\n }]\n });\n };\n\n ctx.ds.query(options).then(function (result) {\n expect(result.data).to.have.length(2);\n expect(result.data.map(t => t.target)).to.include.members(['memory', 'packets']);\n expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n expect(result.data[1].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n }).then(v => done(), err => done(err));\n });\n\n it('should return multiple results with templated target', function (done) {\n\n let options = {\n range: {\n from: 15,\n to: 30\n },\n targets: [{\n target: '$app/memory',\n type: 'gauge',\n rate: false,\n queryBy: 'ids'\n }]\n };\n\n ctx.templateSrv.replace = function(target, vars) {\n expect(target).to.equal('$app');\n return \"{app_1,app_2}\";\n };\n\n ctx.backendSrv.datasourceRequest = function(request) {\n expect(request.url).to.have.string(\"/gauges/raw/query\");\n expect(request.data.ids).to.include.members(['app_1/memory', 'app_2/memory']);\n return ctx.$q.when({\n status: 200,\n data: [{\n id: \"app_1/memory\",\n data: [{\n timestamp: 13,\n value: 15\n }, {\n timestamp: 19,\n value: 21\n }]\n },{\n id: \"app_2/memory\",\n data: [{\n timestamp: 13,\n value: 28\n }, {\n timestamp: 19,\n value: 32\n }]\n }]\n });\n };\n\n ctx.ds.query(options).then(function (result) {\n expect(result.data).to.have.length(2);\n expect(result.data.map(t => t.target)).to.include.members(['app_1/memory', 'app_2/memory']);\n expect(result.data[0].datapoints).to.deep.equal([[15, 13], [21, 19]]);\n expect(result.data[1].datapoints).to.deep.equal([[28, 13], [32, 19]]);\n }).then(v => done(), err => done(err));\n });\n});\n"]}
\ No newline at end of file
diff --git a/dist/test/spec/test-main.js b/dist/test/spec/test-main.js
new file mode 100644
index 0000000..9af663a
--- /dev/null
+++ b/dist/test/spec/test-main.js
@@ -0,0 +1,33 @@
+'use strict';
+
+var _prunk = require('prunk');
+
+var _prunk2 = _interopRequireDefault(_prunk);
+
+var _jsdom = require('jsdom');
+
+var _chai = require('chai');
+
+var _chai2 = _interopRequireDefault(_chai);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// Mock Grafana modules that are not available outside of the core project
+// Required for loading module.js
+_prunk2.default.mock('./css/query-editor.css!', 'no css, dude.');
+_prunk2.default.mock('app/plugins/sdk', {
+ QueryCtrl: null
+});
+
+// Setup jsdom
+// Required for loading angularjs
+global.document = (0, _jsdom.jsdom)('');
+global.window = global.document.parentWindow;
+global.navigator = window.navigator = {};
+global.Node = window.Node;
+
+// Setup Chai
+_chai2.default.should();
+global.assert = _chai2.default.assert;
+global.expect = _chai2.default.expect;
+//# sourceMappingURL=test-main.js.map
diff --git a/dist/test/spec/test-main.js.map b/dist/test/spec/test-main.js.map
new file mode 100644
index 0000000..5946428
--- /dev/null
+++ b/dist/test/spec/test-main.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../../spec/test-main.js"],"names":[],"mappings":";;AAAA;;;;AACA;;AACA;;;;;;AAEA;AACA;AACA,gBAAM,IAAN,CAAW,yBAAX,EAAsC,eAAtC;AACA,gBAAM,IAAN,CAAW,iBAAX,EAA8B;AAC1B,eAAW;AADe,CAA9B;;AAIA;AACA;AACA,OAAO,QAAP,GAAkB,kBAAM,0DAAN,CAAlB;AACA,OAAO,MAAP,GAAgB,OAAO,QAAP,CAAgB,YAAhC;AACA,OAAO,SAAP,GAAmB,OAAO,SAAP,GAAmB,EAAtC;AACA,OAAO,IAAP,GAAc,OAAO,IAArB;;AAEA;AACA,eAAK,MAAL;AACA,OAAO,MAAP,GAAgB,eAAK,MAArB;AACA,OAAO,MAAP,GAAgB,eAAK,MAArB","file":"test-main.js","sourcesContent":["import prunk from 'prunk';\nimport {jsdom} from 'jsdom';\nimport chai from 'chai';\n\n// Mock Grafana modules that are not available outside of the core project\n// Required for loading module.js\nprunk.mock('./css/query-editor.css!', 'no css, dude.');\nprunk.mock('app/plugins/sdk', {\n QueryCtrl: null\n});\n\n// Setup jsdom\n// Required for loading angularjs\nglobal.document = jsdom('');\nglobal.window = global.document.parentWindow;\nglobal.navigator = window.navigator = {};\nglobal.Node = window.Node;\n\n// Setup Chai\nchai.should();\nglobal.assert = chai.assert;\nglobal.expect = chai.expect;\n"]}
\ No newline at end of file
diff --git a/dist/test/spec/variables_spec.js b/dist/test/spec/variables_spec.js
new file mode 100644
index 0000000..21b1716
--- /dev/null
+++ b/dist/test/spec/variables_spec.js
@@ -0,0 +1,51 @@
+"use strict";
+
+var _variables = require("../variables");
+
+var _q = require("q");
+
+var _q2 = _interopRequireDefault(_q);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+describe('Variables', function () {
+ var ctx = {
+ templateSrv: {},
+ variables: {}
+ };
+
+ beforeEach(function () {
+ ctx.templateSrv = {
+ replace: function replace(target, vars) {
+ return target;
+ }
+ };
+ ctx.variables = new _variables.Variables(ctx.templateSrv);
+ });
+
+ it('should resolve single variable', function (done) {
+ ctx.templateSrv.replace = function (target, vars) {
+ expect(target).to.equal('$app');
+ return "{app_1,app_2}";
+ };
+ var resolved = ctx.variables.resolve("$app/memory/usage", {});
+ expect(resolved).to.deep.equal(['app_1/memory/usage', 'app_2/memory/usage']);
+ done();
+ });
+
+ it('should resolve multiple variables', function (done) {
+ ctx.templateSrv.replace = function (target, vars) {
+ if (target === '$app') {
+ return "{app_1,app_2}";
+ }
+ if (target === '$container') {
+ return "{1234,5678,90}";
+ }
+ return target;
+ };
+ var resolved = ctx.variables.resolve("$app/$container/memory/usage", {});
+ expect(resolved).to.deep.equal(['app_1/1234/memory/usage', 'app_2/1234/memory/usage', 'app_1/5678/memory/usage', 'app_2/5678/memory/usage', 'app_1/90/memory/usage', 'app_2/90/memory/usage']);
+ done();
+ });
+});
+//# sourceMappingURL=variables_spec.js.map
diff --git a/dist/test/spec/variables_spec.js.map b/dist/test/spec/variables_spec.js.map
new file mode 100644
index 0000000..95db982
--- /dev/null
+++ b/dist/test/spec/variables_spec.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../../spec/variables_spec.js"],"names":[],"mappings":";;AAAA;;AACA;;;;;;AAEA,SAAS,WAAT,EAAsB,YAAY;AAChC,MAAI,MAAM;AACR,iBAAa,EADL;AAER,eAAW;AAFH,GAAV;;AAKA,aAAW,YAAY;AACrB,QAAI,WAAJ,GAAkB;AACd,eAAS,iBAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC9B,eAAO,MAAP;AACD;AAHa,KAAlB;AAKA,QAAI,SAAJ,GAAgB,yBAAc,IAAI,WAAlB,CAAhB;AACD,GAPD;;AASA,KAAG,gCAAH,EAAqC,UAAU,IAAV,EAAgB;AACnD,QAAI,WAAJ,CAAgB,OAAhB,GAA0B,UAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC/C,aAAO,MAAP,EAAe,EAAf,CAAkB,KAAlB,CAAwB,MAAxB;AACA,aAAO,eAAP;AACD,KAHD;AAIA,QAAI,WAAW,IAAI,SAAJ,CAAc,OAAd,CAAsB,mBAAtB,EAA2C,EAA3C,CAAf;AACA,WAAO,QAAP,EAAiB,EAAjB,CAAoB,IAApB,CAAyB,KAAzB,CAA+B,CAAC,oBAAD,EAAuB,oBAAvB,CAA/B;AACA;AACD,GARD;;AAUA,KAAG,mCAAH,EAAwC,UAAU,IAAV,EAAgB;AACtD,QAAI,WAAJ,CAAgB,OAAhB,GAA0B,UAAS,MAAT,EAAiB,IAAjB,EAAuB;AAC/C,UAAI,WAAW,MAAf,EAAuB;AACrB,eAAO,eAAP;AACD;AACD,UAAI,WAAW,YAAf,EAA6B;AAC3B,eAAO,gBAAP;AACD;AACD,aAAO,MAAP;AACD,KARD;AASA,QAAI,WAAW,IAAI,SAAJ,CAAc,OAAd,CAAsB,8BAAtB,EAAsD,EAAtD,CAAf;AACA,WAAO,QAAP,EAAiB,EAAjB,CAAoB,IAApB,CAAyB,KAAzB,CAA+B,CAC7B,yBAD6B,EAE7B,yBAF6B,EAG7B,yBAH6B,EAI7B,yBAJ6B,EAK7B,uBAL6B,EAM7B,uBAN6B,CAA/B;AAQA;AACD,GApBD;AAqBD,CA9CD","file":"variables_spec.js","sourcesContent":["import {Variables} from \"../variables\";\nimport Q from \"q\";\n\ndescribe('Variables', function () {\n let ctx = {\n templateSrv: {},\n variables: {}\n };\n\n beforeEach(function () {\n ctx.templateSrv = {\n replace: function(target, vars) {\n return target;\n }\n };\n ctx.variables = new Variables(ctx.templateSrv);\n });\n\n it('should resolve single variable', function (done) {\n ctx.templateSrv.replace = function(target, vars) {\n expect(target).to.equal('$app');\n return \"{app_1,app_2}\";\n };\n let resolved = ctx.variables.resolve(\"$app/memory/usage\", {});\n expect(resolved).to.deep.equal(['app_1/memory/usage', 'app_2/memory/usage']);\n done();\n });\n\n it('should resolve multiple variables', function (done) {\n ctx.templateSrv.replace = function(target, vars) {\n if (target === '$app') {\n return \"{app_1,app_2}\";\n }\n if (target === '$container') {\n return \"{1234,5678,90}\";\n }\n return target;\n };\n let resolved = ctx.variables.resolve(\"$app/$container/memory/usage\", {});\n expect(resolved).to.deep.equal([\n 'app_1/1234/memory/usage',\n 'app_2/1234/memory/usage',\n 'app_1/5678/memory/usage',\n 'app_2/5678/memory/usage',\n 'app_1/90/memory/usage',\n 'app_2/90/memory/usage'\n ]);\n done();\n });\n});\n"]}
\ No newline at end of file
diff --git a/dist/test/variables.js b/dist/test/variables.js
new file mode 100644
index 0000000..af8f04b
--- /dev/null
+++ b/dist/test/variables.js
@@ -0,0 +1,55 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Variables = exports.Variables = function () {
+ function Variables(templateSrv) {
+ _classCallCheck(this, Variables);
+
+ this.templateSrv = templateSrv;
+ }
+
+ _createClass(Variables, [{
+ key: 'resolve',
+ value: function resolve(target, options) {
+ var _this = this;
+
+ var variables = options.scopedVars || this.templateSrv.variables;
+ // For each variable in target, and each values of a given variable, build a resolved target string
+ var variableNames = target.match(/\$\w+/g);
+ var resolved = [target];
+ if (variableNames) {
+ variableNames.forEach(function (name) {
+ var values = _this.getVarValues(name, variables);
+ var newResolved = [];
+ values.forEach(function (val) {
+ resolved.forEach(function (target) {
+ newResolved.push(target.replace(name, val));
+ });
+ });
+ resolved = newResolved;
+ });
+ }
+ return resolved;
+ }
+ }, {
+ key: 'getVarValues',
+ value: function getVarValues(name, variables) {
+ var values = this.templateSrv.replace(name, variables);
+ // result might be in like "{id1,id2,id3}" (as string)
+ if (values.startsWith('{')) {
+ return values.substring(1, values.length - 1).split(',');
+ }
+ return [values];
+ }
+ }]);
+
+ return Variables;
+}();
+//# sourceMappingURL=variables.js.map
diff --git a/dist/test/variables.js.map b/dist/test/variables.js.map
new file mode 100644
index 0000000..272ab39
--- /dev/null
+++ b/dist/test/variables.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../../src/variables.js"],"names":[],"mappings":";;;;;;;;;;IAAa,S,WAAA,S;AAEX,qBAAY,WAAZ,EAAyB;AAAA;;AACvB,SAAK,WAAL,GAAmB,WAAnB;AACD;;;;4BAEO,M,EAAQ,O,EAAS;AAAA;;AACvB,UAAI,YAAY,QAAQ,UAAR,IAAsB,KAAK,WAAL,CAAiB,SAAvD;AACA;AACA,UAAI,gBAAgB,OAAO,KAAP,CAAa,QAAb,CAApB;AACA,UAAI,WAAW,CAAC,MAAD,CAAf;AACA,UAAI,aAAJ,EAAmB;AACjB,sBAAc,OAAd,CAAsB,gBAAQ;AAC5B,cAAI,SAAS,MAAK,YAAL,CAAkB,IAAlB,EAAwB,SAAxB,CAAb;AACA,cAAI,cAAc,EAAlB;AACA,iBAAO,OAAP,CAAe,eAAO;AACpB,qBAAS,OAAT,CAAiB,kBAAU;AACzB,0BAAY,IAAZ,CAAiB,OAAO,OAAP,CAAe,IAAf,EAAqB,GAArB,CAAjB;AACD,aAFD;AAGD,WAJD;AAKA,qBAAW,WAAX;AACD,SATD;AAUD;AACD,aAAO,QAAP;AACD;;;iCAEY,I,EAAM,S,EAAW;AAC5B,UAAI,SAAS,KAAK,WAAL,CAAiB,OAAjB,CAAyB,IAAzB,EAA+B,SAA/B,CAAb;AACA;AACA,UAAI,OAAO,UAAP,CAAkB,GAAlB,CAAJ,EAA4B;AACxB,eAAO,OAAO,SAAP,CAAiB,CAAjB,EAAoB,OAAO,MAAP,GAAc,CAAlC,EAAqC,KAArC,CAA2C,GAA3C,CAAP;AACH;AACD,aAAO,CAAC,MAAD,CAAP;AACD","file":"variables.js","sourcesContent":["export class Variables {\n\n constructor(templateSrv) {\n this.templateSrv = templateSrv;\n }\n\n resolve(target, options) {\n let variables = options.scopedVars || this.templateSrv.variables;\n // For each variable in target, and each values of a given variable, build a resolved target string\n let variableNames = target.match(/\\$\\w+/g);\n var resolved = [target];\n if (variableNames) {\n variableNames.forEach(name => {\n let values = this.getVarValues(name, variables);\n let newResolved = [];\n values.forEach(val => {\n resolved.forEach(target => {\n newResolved.push(target.replace(name, val));\n });\n });\n resolved = newResolved;\n });\n }\n return resolved;\n }\n\n getVarValues(name, variables) {\n let values = this.templateSrv.replace(name, variables);\n // result might be in like \"{id1,id2,id3}\" (as string)\n if (values.startsWith('{')) {\n return values.substring(1, values.length-1).split(',');\n }\n return [values];\n }\n}\n"]}
\ No newline at end of file
diff --git a/dist/variables.js b/dist/variables.js
new file mode 100644
index 0000000..ac11b73
--- /dev/null
+++ b/dist/variables.js
@@ -0,0 +1,84 @@
+'use strict';
+
+System.register([], function (_export, _context) {
+ "use strict";
+
+ var _createClass, Variables;
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ return {
+ setters: [],
+ execute: function () {
+ _createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+ _export('Variables', Variables = function () {
+ function Variables(templateSrv) {
+ _classCallCheck(this, Variables);
+
+ this.templateSrv = templateSrv;
+ }
+
+ _createClass(Variables, [{
+ key: 'resolve',
+ value: function resolve(target, options) {
+ var _this = this;
+
+ var variables = options.scopedVars || this.templateSrv.variables;
+ // For each variable in target, and each values of a given variable, build a resolved target string
+ var variableNames = target.match(/\$\w+/g);
+ var resolved = [target];
+ if (variableNames) {
+ variableNames.forEach(function (name) {
+ var values = _this.getVarValues(name, variables);
+ var newResolved = [];
+ values.forEach(function (val) {
+ resolved.forEach(function (target) {
+ newResolved.push(target.replace(name, val));
+ });
+ });
+ resolved = newResolved;
+ });
+ }
+ return resolved;
+ }
+ }, {
+ key: 'getVarValues',
+ value: function getVarValues(name, variables) {
+ var values = this.templateSrv.replace(name, variables);
+ // result might be in like "{id1,id2,id3}" (as string)
+ if (values.startsWith('{')) {
+ return values.substring(1, values.length - 1).split(',');
+ }
+ return [values];
+ }
+ }]);
+
+ return Variables;
+ }());
+
+ _export('Variables', Variables);
+ }
+ };
+});
+//# sourceMappingURL=variables.js.map
diff --git a/dist/variables.js.map b/dist/variables.js.map
new file mode 100644
index 0000000..8e1b054
--- /dev/null
+++ b/dist/variables.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/variables.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAa,S;AAEX,2BAAY,WAAZ,EAAyB;AAAA;;AACvB,eAAK,WAAL,GAAmB,WAAnB;AACD;;;;kCAEO,M,EAAQ,O,EAAS;AAAA;;AACvB,gBAAI,YAAY,QAAQ,UAAR,IAAsB,KAAK,WAAL,CAAiB,SAAvD;AACA;AACA,gBAAI,gBAAgB,OAAO,KAAP,CAAa,QAAb,CAApB;AACA,gBAAI,WAAW,CAAC,MAAD,CAAf;AACA,gBAAI,aAAJ,EAAmB;AACjB,4BAAc,OAAd,CAAsB,gBAAQ;AAC5B,oBAAI,SAAS,MAAK,YAAL,CAAkB,IAAlB,EAAwB,SAAxB,CAAb;AACA,oBAAI,cAAc,EAAlB;AACA,uBAAO,OAAP,CAAe,eAAO;AACpB,2BAAS,OAAT,CAAiB,kBAAU;AACzB,gCAAY,IAAZ,CAAiB,OAAO,OAAP,CAAe,IAAf,EAAqB,GAArB,CAAjB;AACD,mBAFD;AAGD,iBAJD;AAKA,2BAAW,WAAX;AACD,eATD;AAUD;AACD,mBAAO,QAAP;AACD;;;uCAEY,I,EAAM,S,EAAW;AAC5B,gBAAI,SAAS,KAAK,WAAL,CAAiB,OAAjB,CAAyB,IAAzB,EAA+B,SAA/B,CAAb;AACA;AACA,gBAAI,OAAO,UAAP,CAAkB,GAAlB,CAAJ,EAA4B;AACxB,qBAAO,OAAO,SAAP,CAAiB,CAAjB,EAAoB,OAAO,MAAP,GAAc,CAAlC,EAAqC,KAArC,CAA2C,GAA3C,CAAP;AACH;AACD,mBAAO,CAAC,MAAD,CAAP;AACD","file":"variables.js","sourcesContent":["export class Variables {\n\n constructor(templateSrv) {\n this.templateSrv = templateSrv;\n }\n\n resolve(target, options) {\n let variables = options.scopedVars || this.templateSrv.variables;\n // For each variable in target, and each values of a given variable, build a resolved target string\n let variableNames = target.match(/\\$\\w+/g);\n var resolved = [target];\n if (variableNames) {\n variableNames.forEach(name => {\n let values = this.getVarValues(name, variables);\n let newResolved = [];\n values.forEach(val => {\n resolved.forEach(target => {\n newResolved.push(target.replace(name, val));\n });\n });\n resolved = newResolved;\n });\n }\n return resolved;\n }\n\n getVarValues(name, variables) {\n let values = this.templateSrv.replace(name, variables);\n // result might be in like \"{id1,id2,id3}\" (as string)\n if (values.startsWith('{')) {\n return values.substring(1, values.length-1).split(',');\n }\n return [values];\n }\n}\n"]}
\ No newline at end of file