diff --git a/public/app/core/core.ts b/public/app/core/core.ts
index 0b120dd85b7..c216151f2dc 100644
--- a/public/app/core/core.ts
+++ b/public/app/core/core.ts
@@ -16,6 +16,8 @@ import "./directives/password_strenght";
import "./directives/spectrum_picker";
import "./directives/tags";
import "./directives/value_select_dropdown";
+import "./directives/plugin_directive_loader";
+import "./directives/rebuild_on_change";
import "./directives/give_focus";
import './jquery_extended';
import './partials';
diff --git a/public/app/core/directives/plugin_directive_loader.ts b/public/app/core/directives/plugin_directive_loader.ts
new file mode 100644
index 00000000000..b6abb91b065
--- /dev/null
+++ b/public/app/core/directives/plugin_directive_loader.ts
@@ -0,0 +1,92 @@
+///
+
+import angular from 'angular';
+import _ from 'lodash';
+
+import coreModule from '../core_module';
+
+function pluginDirectiveLoader($compile, datasourceSrv) {
+
+ function getPluginComponentDirective(options) {
+ return function() {
+ return {
+ templateUrl: options.Component.templateUrl,
+ restrict: 'E',
+ controller: options.Component,
+ controllerAs: 'ctrl',
+ bindToController: true,
+ scope: options.bindings,
+ link: (scope, elem, attrs, ctrl) => {
+ if (ctrl.link) {
+ ctrl.link(scope, elem, attrs, ctrl);
+ }
+ }
+ };
+ };
+ }
+
+ function getModule(scope, attrs) {
+ switch (attrs.type) {
+ case "metrics-query-editor":
+ let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
+ return datasourceSrv.get(datasource).then(ds => {
+ if (!scope.target.refId) {
+ scope.target.refId = 'A';
+ }
+
+ return System.import(ds.meta.module).then(dsModule => {
+ return {
+ name: 'metrics-query-editor-' + ds.meta.id,
+ bindings: {target: "=", panelCtrl: "="},
+ attrs: {"target": "target", "panel-ctrl": "ctrl"},
+ Component: dsModule.MetricsQueryEditor
+ };
+ });
+ });
+ case 'datasource-config-view':
+ return System.import(scope.datasourceMeta.module).then(function(dsModule) {
+ return {
+ name: 'ds-config-' + scope.datasourceMeta.id,
+ bindings: {meta: "=", current: "="},
+ attrs: {meta: "datasourceMeta", current: "current"},
+ Component: dsModule.ConfigView,
+ };
+ });
+ }
+ }
+
+ function appendAndCompile(scope, elem, componentInfo) {
+ console.log('compile', elem, componentInfo);
+ var child = angular.element(document.createElement(componentInfo.name));
+ _.each(componentInfo.attrs, (value, key) => {
+ child.attr(key, value);
+ });
+
+ $compile(child)(scope);
+
+ elem.empty();
+ elem.append(child);
+ }
+
+ function registerPluginComponent(scope, elem, attrs, componentInfo) {
+ if (!componentInfo.Component.registered) {
+ var directiveName = attrs.$normalize(componentInfo.name);
+ var directiveFn = getPluginComponentDirective(componentInfo);
+ coreModule.directive(directiveName, directiveFn);
+ componentInfo.Component.registered = true;
+ }
+
+ appendAndCompile(scope, elem, componentInfo);
+ }
+
+ return {
+ restrict: 'E',
+ link: function(scope, elem, attrs) {
+ getModule(scope, attrs).then(function (componentInfo) {
+ registerPluginComponent(scope, elem, attrs, componentInfo);
+ });
+ }
+ };
+}
+
+coreModule.directive('pluginDirectiveLoader', pluginDirectiveLoader);
diff --git a/public/app/core/directives/rebuild_on_change.ts b/public/app/core/directives/rebuild_on_change.ts
new file mode 100644
index 00000000000..3a9399c61ed
--- /dev/null
+++ b/public/app/core/directives/rebuild_on_change.ts
@@ -0,0 +1,58 @@
+///
+
+import angular from 'angular';
+import _ from 'lodash';
+import $ from 'jquery';
+
+import coreModule from '../core_module';
+
+function getBlockNodes(nodes) {
+ var node = nodes[0];
+ var endNode = nodes[nodes.length - 1];
+ var blockNodes;
+
+ for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
+ if (blockNodes || nodes[i] !== node) {
+ if (!blockNodes) {
+ blockNodes = $([].slice.call(nodes, 0, i));
+ }
+ blockNodes.push(node);
+ }
+ }
+
+ return blockNodes || nodes;
+}
+
+function rebuildOnChange($compile) {
+
+ return {
+ transclude: true,
+ priority: 600,
+ restrict: 'A',
+ link: function(scope, elem, attrs, ctrl, transclude) {
+ var childScope, previousElements;
+ var uncompiledHtml;
+
+ scope.$watch(attrs.rebuildOnChange, function rebuildOnChangeAction(value) {
+
+ if (childScope) {
+ childScope.$destroy();
+ childScope = null;
+ elem.empty();
+ }
+
+ if (value) {
+ if (!childScope) {
+ transclude(function(clone, newScope) {
+ childScope = newScope;
+ elem.append($compile(clone)(childScope));
+ });
+ }
+ }
+
+ });
+ }
+ };
+}
+
+coreModule.directive('rebuildOnChange', rebuildOnChange);
diff --git a/public/app/features/datasources/partials/edit.html b/public/app/features/datasources/partials/edit.html
index 3ebae573ebd..5b9facb83a8 100644
--- a/public/app/features/datasources/partials/edit.html
+++ b/public/app/features/datasources/partials/edit.html
@@ -41,7 +41,12 @@
-
+
+
+
Testing....
diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts
index ab3d6001e67..63484785d75 100644
--- a/public/app/features/panel/panel_directive.ts
+++ b/public/app/features/panel/panel_directive.ts
@@ -50,7 +50,7 @@ var module = angular.module('grafana.directives');
module.directive('grafanaPanel', function() {
return {
restrict: 'E',
- templateUrl: 'app/features/panel/partials/panel.html',
+ templateUrl: 'public/app/features/panel/partials/panel.html',
transclude: true,
scope: { ctrl: "=" },
link: function(scope, elem) {
diff --git a/public/app/features/panel/query_editor.ts b/public/app/features/panel/query_editor.ts
index c456f42cc40..8e43019fdf3 100644
--- a/public/app/features/panel/query_editor.ts
+++ b/public/app/features/panel/query_editor.ts
@@ -5,105 +5,6 @@ import _ from 'lodash';
var directivesModule = angular.module('grafana.directives');
-function pluginDirectiveLoader($compile, datasourceSrv) {
-
- function getPluginComponentDirective(options) {
- return function() {
- return {
- templateUrl: options.Component.templateUrl,
- restrict: 'E',
- controller: options.Component,
- controllerAs: 'ctrl',
- bindToController: true,
- scope: options.bindings,
- link: (scope, elem, attrs, ctrl) => {
- if (ctrl.link) {
- ctrl.link(scope, elem, attrs, ctrl);
- }
- }
- };
- };
- }
-
- function getModule(scope, attrs) {
- switch (attrs.type) {
- case "metrics-query-editor": {
- let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
- return datasourceSrv.get(datasource).then(ds => {
- if (!scope.target.refId) {
- scope.target.refId = 'A';
- }
-
- return System.import(ds.meta.module).then(dsModule => {
- return {
- name: 'metrics-query-editor-' + ds.meta.id,
- bindings: {target: "=", panelCtrl: "="},
- attrs: {"target": "target", "panel-ctrl": "ctrl"},
- Component: dsModule.MetricsQueryEditor
- };
- });
- });
- }
- }
- }
-
- function appendAndCompile(scope, elem, componentInfo) {
- var child = angular.element(document.createElement(componentInfo.name));
- _.each(componentInfo.attrs, (value, key) => {
- child.attr(key, value);
- });
-
- $compile(child)(scope);
-
- elem.empty();
- elem.append(child);
- }
-
- function registerPluginComponent(scope, elem, attrs, componentInfo) {
- if (!componentInfo.Component.registered) {
- var directiveName = attrs.$normalize(componentInfo.name);
- var directiveFn = getPluginComponentDirective(componentInfo);
- directivesModule.directive(directiveName, directiveFn);
- componentInfo.Component.registered = true;
- }
-
- appendAndCompile(scope, elem, componentInfo);
- }
-
- return {
- restrict: 'E',
- link: function(scope, elem, attrs) {
- getModule(scope, attrs).then(function (componentInfo) {
- registerPluginComponent(scope, elem, attrs, componentInfo);
- });
- }
- };
-}
-
-/** @ngInject */
-function metricsQueryEditor(dynamicDirectiveSrv, datasourceSrv) {
- return dynamicDirectiveSrv.create({
- watchPath: "ctrl.panel.datasource",
- directive: scope => {
- let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
- return datasourceSrv.get(datasource).then(ds => {
- scope.datasource = ds;
-
- if (!scope.target.refId) {
- scope.target.refId = 'A';
- }
-
- return System.import(ds.meta.module).then(dsModule => {
- return {
- name: 'metrics-query-editor-' + ds.meta.id,
- fn: dsModule.metricsQueryEditor,
- };
- });
- });
- }
- });
-}
-
/** @ngInject */
function metricsQueryOptions(dynamicDirectiveSrv, datasourceSrv) {
return dynamicDirectiveSrv.create({
@@ -121,6 +22,4 @@ function metricsQueryOptions(dynamicDirectiveSrv, datasourceSrv) {
});
}
-directivesModule.directive('pluginDirectiveLoader', pluginDirectiveLoader);
-directivesModule.directive('metricsQueryEditor', metricsQueryEditor);
directivesModule.directive('metricsQueryOptions', metricsQueryOptions);
diff --git a/public/app/plugins/datasource/graphite/module.js b/public/app/plugins/datasource/graphite/module.js
index 64f0945aef3..a1d4ed5fc2b 100644
--- a/public/app/plugins/datasource/graphite/module.js
+++ b/public/app/plugins/datasource/graphite/module.js
@@ -23,11 +23,16 @@ function (GraphiteDatasource) {
return {templateUrl: 'public/app/plugins/datasource/graphite/partials/config.html'};
}
+ function ConfigView() {
+ }
+ ConfigView.templateUrl = 'public/app/plugins/datasource/graphite/partials/config.html';
+
return {
Datasource: GraphiteDatasource,
configView: configView,
annotationsQueryEditor: annotationsQueryEditor,
metricsQueryEditor: metricsQueryEditor,
metricsQueryOptions: metricsQueryOptions,
+ ConfigView: ConfigView
};
});
diff --git a/public/app/plugins/datasource/prometheus/datasource.d.ts b/public/app/plugins/datasource/prometheus/datasource.d.ts
deleted file mode 100644
index a50d7ca49cc..00000000000
--- a/public/app/plugins/datasource/prometheus/datasource.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-declare var Datasource: any;
-export default Datasource;
-
diff --git a/public/app/plugins/datasource/prometheus/datasource.js b/public/app/plugins/datasource/prometheus/datasource.js
deleted file mode 100644
index 6b35a966e85..00000000000
--- a/public/app/plugins/datasource/prometheus/datasource.js
+++ /dev/null
@@ -1,282 +0,0 @@
-define([
- 'angular',
- 'lodash',
- 'moment',
- 'app/core/utils/datemath',
- './query_ctrl',
-],
-function (angular, _, moment, dateMath) {
- 'use strict';
-
- var durationSplitRegexp = /(\d+)(ms|s|m|h|d|w|M|y)/;
-
- /** @ngInject */
- function PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv) {
- this.type = 'prometheus';
- this.editorSrc = 'app/features/prometheus/partials/query.editor.html';
- this.name = instanceSettings.name;
- this.supportMetrics = true;
- this.url = instanceSettings.url;
- this.directUrl = instanceSettings.directUrl;
- this.basicAuth = instanceSettings.basicAuth;
- this.withCredentials = instanceSettings.withCredentials;
- this.lastErrors = {};
-
- this._request = function(method, url) {
- var options = {
- url: this.url + url,
- method: method
- };
-
- if (this.basicAuth || this.withCredentials) {
- options.withCredentials = true;
- }
- if (this.basicAuth) {
- options.headers = {
- "Authorization": this.basicAuth
- };
- }
-
- return backendSrv.datasourceRequest(options);
- };
-
- // Called once per panel (graph)
- this.query = function(options) {
- var start = getPrometheusTime(options.range.from, false);
- var end = getPrometheusTime(options.range.to, true);
-
- var queries = [];
- options = _.clone(options);
- _.each(options.targets, _.bind(function(target) {
- if (!target.expr || target.hide) {
- return;
- }
-
- var query = {};
- query.expr = templateSrv.replace(target.expr, options.scopedVars);
-
- var interval = target.interval || options.interval;
- var intervalFactor = target.intervalFactor || 1;
- target.step = query.step = this.calculateInterval(interval, intervalFactor);
- var range = Math.ceil(end - start);
- // Prometheus drop query if range/step > 11000
- // calibrate step if it is too big
- if (query.step !== 0 && range / query.step > 11000) {
- target.step = query.step = Math.ceil(range / 11000);
- }
-
- queries.push(query);
- }, this));
-
- // No valid targets, return the empty result to save a round trip.
- if (_.isEmpty(queries)) {
- var d = $q.defer();
- d.resolve({ data: [] });
- return d.promise;
- }
-
- var allQueryPromise = _.map(queries, _.bind(function(query) {
- return this.performTimeSeriesQuery(query, start, end);
- }, this));
-
- var self = this;
- return $q.all(allQueryPromise)
- .then(function(allResponse) {
- var result = [];
-
- _.each(allResponse, function(response, index) {
- if (response.status === 'error') {
- self.lastErrors.query = response.error;
- throw response.error;
- }
- delete self.lastErrors.query;
-
- _.each(response.data.data.result, function(metricData) {
- result.push(transformMetricData(metricData, options.targets[index], start, end));
- });
- });
-
- return { data: result };
- });
- };
-
- this.performTimeSeriesQuery = function(query, start, end) {
- var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step;
- return this._request('GET', url);
- };
-
- this.performSuggestQuery = function(query) {
- var url = '/api/v1/label/__name__/values';
-
- return this._request('GET', url).then(function(result) {
- return _.filter(result.data.data, function (metricName) {
- return metricName.indexOf(query) !== 1;
- });
- });
- };
-
- this.metricFindQuery = function(query) {
- if (!query) { return $q.when([]); }
-
- var interpolated;
- try {
- interpolated = templateSrv.replace(query);
- }
- catch (err) {
- return $q.reject(err);
- }
-
- var label_values_regex = /^label_values\(([^,]+)(?:,\s*(.+))?\)$/;
- var metric_names_regex = /^metrics\((.+)\)$/;
-
- var url;
- var label_values_query = interpolated.match(label_values_regex);
- if (label_values_query) {
- if (!label_values_query[2]) {
- // return label values globally
- url = '/api/v1/label/' + label_values_query[1] + '/values';
-
- return this._request('GET', url).then(function(result) {
- return _.map(result.data.data, function(value) {
- return {text: value};
- });
- });
- } else {
- url = '/api/v1/series?match[]=' + encodeURIComponent(label_values_query[1]);
-
- return this._request('GET', url)
- .then(function(result) {
- return _.map(result.data.data, function(metric) {
- return {
- text: metric[label_values_query[2]],
- expandable: true
- };
- });
- });
- }
- }
-
- var metric_names_query = interpolated.match(metric_names_regex);
- if (metric_names_query) {
- url = '/api/v1/label/__name__/values';
-
- return this._request('GET', url)
- .then(function(result) {
- return _.chain(result.data.data)
- .filter(function(metricName) {
- var r = new RegExp(metric_names_query[1]);
- return r.test(metricName);
- })
- .map(function(matchedMetricName) {
- return {
- text: matchedMetricName,
- expandable: true
- };
- })
- .value();
- });
- } else {
- // if query contains full metric name, return metric name and label list
- url = '/api/v1/series?match[]=' + encodeURIComponent(interpolated);
-
- return this._request('GET', url)
- .then(function(result) {
- return _.map(result.data.data, function(metric) {
- return {
- text: getOriginalMetricName(metric),
- expandable: true
- };
- });
- });
- }
- };
-
- this.testDatasource = function() {
- return this.metricFindQuery('metrics(.*)').then(function() {
- return { status: 'success', message: 'Data source is working', title: 'Success' };
- });
- };
-
- PrometheusDatasource.prototype.calculateInterval = function(interval, intervalFactor) {
- var m = interval.match(durationSplitRegexp);
- var dur = moment.duration(parseInt(m[1]), m[2]);
- var sec = dur.asSeconds();
- if (sec < 1) {
- sec = 1;
- }
-
- return Math.ceil(sec * intervalFactor);
- };
-
- function transformMetricData(md, options, start, end) {
- var dps = [],
- metricLabel = null;
-
- metricLabel = createMetricLabel(md.metric, options);
-
- var stepMs = parseInt(options.step) * 1000;
- var baseTimestamp = start * 1000;
- _.each(md.values, function(value) {
- var dp_value = parseFloat(value[1]);
- if (_.isNaN(dp_value)) {
- dp_value = null;
- }
-
- var timestamp = value[0] * 1000;
- for (var t = baseTimestamp; t < timestamp; t += stepMs) {
- dps.push([null, t]);
- }
- baseTimestamp = timestamp + stepMs;
- dps.push([dp_value, timestamp]);
- });
-
- var endTimestamp = end * 1000;
- for (var t = baseTimestamp; t <= endTimestamp; t += stepMs) {
- dps.push([null, t]);
- }
-
- return { target: metricLabel, datapoints: dps };
- }
-
- function createMetricLabel(labelData, options) {
- if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
- return getOriginalMetricName(labelData);
- }
-
- var originalSettings = _.templateSettings;
- _.templateSettings = {
- interpolate: /\{\{(.+?)\}\}/g
- };
-
- var template = _.template(templateSrv.replace(options.legendFormat));
- var metricName;
- try {
- metricName = template(labelData);
- } catch (e) {
- metricName = '{}';
- }
-
- _.templateSettings = originalSettings;
-
- return metricName;
- }
-
- function getOriginalMetricName(labelData) {
- var metricName = labelData.__name__ || '';
- delete labelData.__name__;
- var labelPart = _.map(_.pairs(labelData), function(label) {
- return label[0] + '="' + label[1] + '"';
- }).join(',');
- return metricName + '{' + labelPart + '}';
- }
-
- function getPrometheusTime(date, roundUp) {
- if (_.isString(date)) {
- date = dateMath.parse(date, roundUp);
- }
- return (date.valueOf() / 1000).toFixed(0);
- }
- }
-
- return PrometheusDatasource;
-});
diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts
new file mode 100644
index 00000000000..9b754b58eb3
--- /dev/null
+++ b/public/app/plugins/datasource/prometheus/datasource.ts
@@ -0,0 +1,278 @@
+///
+
+import angular from 'angular';
+import _ from 'lodash';
+import moment from 'moment';
+
+import * as dateMath from 'app/core/utils/datemath';
+
+var durationSplitRegexp = /(\d+)(ms|s|m|h|d|w|M|y)/;
+
+/** @ngInject */
+function PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv) {
+ this.type = 'prometheus';
+ this.editorSrc = 'app/features/prometheus/partials/query.editor.html';
+ this.name = instanceSettings.name;
+ this.supportMetrics = true;
+ this.url = instanceSettings.url;
+ this.directUrl = instanceSettings.directUrl;
+ this.basicAuth = instanceSettings.basicAuth;
+ this.withCredentials = instanceSettings.withCredentials;
+ this.lastErrors = {};
+
+ this._request = function(method, url) {
+ var options: any = {
+ url: this.url + url,
+ method: method
+ };
+
+ if (this.basicAuth || this.withCredentials) {
+ options.withCredentials = true;
+ }
+ if (this.basicAuth) {
+ options.headers = {
+ "Authorization": this.basicAuth
+ };
+ }
+
+ return backendSrv.datasourceRequest(options);
+ };
+
+ // Called once per panel (graph)
+ this.query = function(options) {
+ var start = getPrometheusTime(options.range.from, false);
+ var end = getPrometheusTime(options.range.to, true);
+
+ var queries = [];
+ options = _.clone(options);
+ _.each(options.targets, _.bind(function(target) {
+ if (!target.expr || target.hide) {
+ return;
+ }
+
+ var query: any = {};
+ query.expr = templateSrv.replace(target.expr, options.scopedVars);
+
+ var interval = target.interval || options.interval;
+ var intervalFactor = target.intervalFactor || 1;
+ target.step = query.step = this.calculateInterval(interval, intervalFactor);
+ var range = Math.ceil(end - start);
+ // Prometheus drop query if range/step > 11000
+ // calibrate step if it is too big
+ if (query.step !== 0 && range / query.step > 11000) {
+ target.step = query.step = Math.ceil(range / 11000);
+ }
+
+ queries.push(query);
+ }, this));
+
+ // No valid targets, return the empty result to save a round trip.
+ if (_.isEmpty(queries)) {
+ var d = $q.defer();
+ d.resolve({ data: [] });
+ return d.promise;
+ }
+
+ var allQueryPromise = _.map(queries, _.bind(function(query) {
+ return this.performTimeSeriesQuery(query, start, end);
+ }, this));
+
+ var self = this;
+ return $q.all(allQueryPromise)
+ .then(function(allResponse) {
+ var result = [];
+
+ _.each(allResponse, function(response, index) {
+ if (response.status === 'error') {
+ self.lastErrors.query = response.error;
+ throw response.error;
+ }
+ delete self.lastErrors.query;
+
+ _.each(response.data.data.result, function(metricData) {
+ result.push(transformMetricData(metricData, options.targets[index], start, end));
+ });
+ });
+
+ return { data: result };
+ });
+ };
+
+ this.performTimeSeriesQuery = function(query, start, end) {
+ var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step;
+ return this._request('GET', url);
+ };
+
+ this.performSuggestQuery = function(query) {
+ var url = '/api/v1/label/__name__/values';
+
+ return this._request('GET', url).then(function(result) {
+ return _.filter(result.data.data, function (metricName) {
+ return metricName.indexOf(query) !== 1;
+ });
+ });
+ };
+
+ this.metricFindQuery = function(query) {
+ if (!query) { return $q.when([]); }
+
+ var interpolated;
+ try {
+ interpolated = templateSrv.replace(query);
+ } catch (err) {
+ return $q.reject(err);
+ }
+
+ var label_values_regex = /^label_values\(([^,]+)(?:,\s*(.+))?\)$/;
+ var metric_names_regex = /^metrics\((.+)\)$/;
+
+ var url;
+ var label_values_query = interpolated.match(label_values_regex);
+ if (label_values_query) {
+ if (!label_values_query[2]) {
+ // return label values globally
+ url = '/api/v1/label/' + label_values_query[1] + '/values';
+
+ return this._request('GET', url).then(function(result) {
+ return _.map(result.data.data, function(value) {
+ return {text: value};
+ });
+ });
+ } else {
+ url = '/api/v1/series?match[]=' + encodeURIComponent(label_values_query[1]);
+
+ return this._request('GET', url)
+ .then(function(result) {
+ return _.map(result.data.data, function(metric) {
+ return {
+ text: metric[label_values_query[2]],
+ expandable: true
+ };
+ });
+ });
+ }
+ }
+
+ var metric_names_query = interpolated.match(metric_names_regex);
+ if (metric_names_query) {
+ url = '/api/v1/label/__name__/values';
+
+ return this._request('GET', url)
+ .then(function(result) {
+ return _.chain(result.data.data)
+ .filter(function(metricName) {
+ var r = new RegExp(metric_names_query[1]);
+ return r.test(metricName);
+ })
+ .map(function(matchedMetricName) {
+ return {
+ text: matchedMetricName,
+ expandable: true
+ };
+ })
+ .value();
+ });
+ } else {
+ // if query contains full metric name, return metric name and label list
+ url = '/api/v1/series?match[]=' + encodeURIComponent(interpolated);
+
+ return this._request('GET', url)
+ .then(function(result) {
+ return _.map(result.data.data, function(metric) {
+ return {
+ text: getOriginalMetricName(metric),
+ expandable: true
+ };
+ });
+ });
+ }
+ };
+
+ this.testDatasource = function() {
+ return this.metricFindQuery('metrics(.*)').then(function() {
+ return { status: 'success', message: 'Data source is working', title: 'Success' };
+ });
+ };
+
+ PrometheusDatasource.prototype.calculateInterval = function(interval, intervalFactor) {
+ var m = interval.match(durationSplitRegexp);
+ var dur = moment.duration(parseInt(m[1]), m[2]);
+ var sec = dur.asSeconds();
+ if (sec < 1) {
+ sec = 1;
+ }
+
+ return Math.ceil(sec * intervalFactor);
+ };
+
+ function transformMetricData(md, options, start, end) {
+ var dps = [],
+ metricLabel = null;
+
+ metricLabel = createMetricLabel(md.metric, options);
+
+ var stepMs = parseInt(options.step) * 1000;
+ var baseTimestamp = start * 1000;
+ _.each(md.values, function(value) {
+ var dp_value = parseFloat(value[1]);
+ if (_.isNaN(dp_value)) {
+ dp_value = null;
+ }
+
+ var timestamp = value[0] * 1000;
+ for (var t = baseTimestamp; t < timestamp; t += stepMs) {
+ dps.push([null, t]);
+ }
+ baseTimestamp = timestamp + stepMs;
+ dps.push([dp_value, timestamp]);
+ });
+
+ var endTimestamp = end * 1000;
+ for (var t = baseTimestamp; t <= endTimestamp; t += stepMs) {
+ dps.push([null, t]);
+ }
+
+ return { target: metricLabel, datapoints: dps };
+ }
+
+ function createMetricLabel(labelData, options) {
+ if (_.isUndefined(options) || _.isEmpty(options.legendFormat)) {
+ return getOriginalMetricName(labelData);
+ }
+
+ var originalSettings = _.templateSettings;
+ _.templateSettings = {
+ interpolate: /\{\{(.+?)\}\}/g
+ };
+
+ var template = _.template(templateSrv.replace(options.legendFormat));
+ var metricName;
+ try {
+ metricName = template(labelData);
+ } catch (e) {
+ metricName = '{}';
+ }
+
+ _.templateSettings = originalSettings;
+
+ return metricName;
+ }
+
+ function getOriginalMetricName(labelData) {
+ var metricName = labelData.__name__ || '';
+ delete labelData.__name__;
+ var labelPart = _.map(_.pairs(labelData), function(label) {
+ return label[0] + '="' + label[1] + '"';
+ }).join(',');
+ return metricName + '{' + labelPart + '}';
+ }
+
+ function getPrometheusTime(date, roundUp): number {
+ if (_.isString(date)) {
+ date = dateMath.parse(date, roundUp);
+ }
+ return Math.floor(date.valueOf() / 1000);
+ }
+}
+
+export {PrometheusDatasource};
diff --git a/public/app/plugins/datasource/prometheus/module.js b/public/app/plugins/datasource/prometheus/module.js
deleted file mode 100644
index 042224c2e38..00000000000
--- a/public/app/plugins/datasource/prometheus/module.js
+++ /dev/null
@@ -1,20 +0,0 @@
-define([
- './datasource',
-],
-function (PromDatasource) {
- 'use strict';
-
- function metricsQueryEditor() {
- return {controller: 'PrometheusQueryCtrl', templateUrl: 'public/app/plugins/datasource/prometheus/partials/query.editor.html'};
- }
-
- function configView() {
- return {templateUrl: 'public/app/plugins/datasource/prometheus/partials/config.html'};
- }
-
- return {
- Datasource: PromDatasource,
- metricsQueryEditor: metricsQueryEditor,
- configView: configView,
- };
-});
diff --git a/public/app/plugins/datasource/prometheus/module.ts b/public/app/plugins/datasource/prometheus/module.ts
new file mode 100644
index 00000000000..b04bd10004d
--- /dev/null
+++ b/public/app/plugins/datasource/prometheus/module.ts
@@ -0,0 +1,23 @@
+import {PrometheusDatasource} from './datasource';
+import {PrometheusQueryCtrl} from './query_ctrl';
+
+
+
+
+ // function metricsQueryEditor() {
+ // return {controller: 'PrometheusQueryCtrl', templateUrl: 'public/app/plugins/datasource/prometheus/partials/query.editor.html'};
+ // }
+ //
+ // function configView() {
+ // return {templateUrl: ''};
+ // }
+
+class PrometheusConfigViewCtrl {
+ static templateUrl = 'public/app/plugins/datasource/prometheus/partials/config.html';
+}
+
+export {
+ PrometheusDatasource as Datasource,
+ PrometheusQueryCtrl as MetricsQueryEditor,
+ PrometheusConfigViewCtrl as ConfigView
+};
diff --git a/public/app/plugins/datasource/prometheus/query_ctrl.js b/public/app/plugins/datasource/prometheus/query_ctrl.js
deleted file mode 100644
index b78152c62d0..00000000000
--- a/public/app/plugins/datasource/prometheus/query_ctrl.js
+++ /dev/null
@@ -1,67 +0,0 @@
-define([
- 'angular',
- 'lodash',
-],
-function (angular, _) {
- 'use strict';
-
- var module = angular.module('grafana.controllers');
-
- module.controller('PrometheusQueryCtrl', function($scope, templateSrv) {
- $scope.panelCtrl = $scope.ctrl;
- $scope.panel = $scope.panelCtrl.panel;
-
- $scope.init = function() {
- var target = $scope.target;
-
- target.expr = target.expr || '';
- target.intervalFactor = target.intervalFactor || 2;
-
- $scope.metric = '';
- $scope.resolutions = _.map([1,2,3,4,5,10], function(f) {
- return {factor: f, label: '1/' + f};
- });
-
- $scope.$on('typeahead-updated', function() {
- $scope.$apply($scope.inputMetric);
- $scope.refreshMetricData();
- });
- };
-
- $scope.refreshMetricData = function() {
- if (!_.isEqual($scope.oldTarget, $scope.target)) {
- $scope.oldTarget = angular.copy($scope.target);
- $scope.paneCtrl.refresh();
- }
- };
-
- $scope.inputMetric = function() {
- $scope.target.expr += $scope.target.metric;
- $scope.metric = '';
- };
-
- $scope.suggestMetrics = function(query, callback) {
- $scope.datasource
- .performSuggestQuery(query)
- .then(callback);
- };
-
- $scope.linkToPrometheus = function() {
- var range = Math.ceil(($scope.range.to.valueOf() - $scope.range.from.valueOf()) / 1000);
- var endTime = $scope.range.to.utc().format('YYYY-MM-DD HH:mm');
- var expr = {
- expr: templateSrv.replace($scope.target.expr, $scope.panel.scopedVars),
- range_input: range + 's',
- end_input: endTime,
- step_input: '',
- stacked: $scope.panel.stack,
- tab: 0
- };
- var hash = encodeURIComponent(JSON.stringify([expr]));
- return $scope.datasource.directUrl + '/graph#' + hash;
- };
-
- $scope.init();
- });
-
-});
diff --git a/public/app/plugins/datasource/prometheus/query_ctrl.ts b/public/app/plugins/datasource/prometheus/query_ctrl.ts
new file mode 100644
index 00000000000..e0fd9aea02d
--- /dev/null
+++ b/public/app/plugins/datasource/prometheus/query_ctrl.ts
@@ -0,0 +1,66 @@
+///
+
+import angular from 'angular';
+import _ from 'lodash';
+import moment from 'moment';
+
+import * as dateMath from 'app/core/utils/datemath';
+
+function PrometheusQueryCtrl($scope, templateSrv) {
+ $scope.panelCtrl = $scope.ctrl;
+ $scope.panel = $scope.panelCtrl.panel;
+
+ $scope.init = function() {
+ var target = $scope.target;
+
+ target.expr = target.expr || '';
+ target.intervalFactor = target.intervalFactor || 2;
+
+ $scope.metric = '';
+ $scope.resolutions = _.map([1,2,3,4,5,10], function(f) {
+ return {factor: f, label: '1/' + f};
+ });
+
+ $scope.$on('typeahead-updated', function() {
+ $scope.$apply($scope.inputMetric);
+ $scope.refreshMetricData();
+ });
+ };
+
+ $scope.refreshMetricData = function() {
+ if (!_.isEqual($scope.oldTarget, $scope.target)) {
+ $scope.oldTarget = angular.copy($scope.target);
+ $scope.paneCtrl.refresh();
+ }
+ };
+
+ $scope.inputMetric = function() {
+ $scope.target.expr += $scope.target.metric;
+ $scope.metric = '';
+ };
+
+ $scope.suggestMetrics = function(query, callback) {
+ $scope.datasource
+ .performSuggestQuery(query)
+ .then(callback);
+ };
+
+ $scope.linkToPrometheus = function() {
+ var range = Math.ceil(($scope.range.to.valueOf() - $scope.range.from.valueOf()) / 1000);
+ var endTime = $scope.range.to.utc().format('YYYY-MM-DD HH:mm');
+ var expr = {
+ expr: templateSrv.replace($scope.target.expr, $scope.panel.scopedVars),
+ range_input: range + 's',
+ end_input: endTime,
+ step_input: '',
+ stacked: $scope.panel.stack,
+ tab: 0
+ };
+ var hash = encodeURIComponent(JSON.stringify([expr]));
+ return $scope.datasource.directUrl + '/graph#' + hash;
+ };
+
+ $scope.init();
+}
+
+export {PrometheusQueryCtrl};
diff --git a/public/views/index.html b/public/views/index.html
index 728cd084c88..1d612e53385 100644
--- a/public/views/index.html
+++ b/public/views/index.html
@@ -59,7 +59,6 @@
-