diff --git a/public/app/plugins/datasource/opentsdb/queryCtrl.js b/public/app/plugins/datasource/opentsdb/queryCtrl.js
deleted file mode 100644
index 04259382390..00000000000
--- a/public/app/plugins/datasource/opentsdb/queryCtrl.js
+++ /dev/null
@@ -1,127 +0,0 @@
-define([
- 'angular',
- 'lodash',
- 'app/core/utils/kbn'
-],
-function (angular, _, kbn) {
- 'use strict';
-
- var module = angular.module('grafana.controllers');
-
- module.controller('OpenTSDBQueryCtrl', function($scope) {
- $scope.panelCtrl = $scope.ctrl;
-
- $scope.init = function() {
- $scope.target.errors = validateTarget($scope.target);
- $scope.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];
- $scope.fillPolicies = ['none', 'nan', 'null', 'zero'];
-
- if (!$scope.target.aggregator) {
- $scope.target.aggregator = 'sum';
- }
-
- if (!$scope.target.downsampleAggregator) {
- $scope.target.downsampleAggregator = 'avg';
- }
-
- if (!$scope.target.downsampleFillPolicy) {
- $scope.target.downsampleFillPolicy = 'none';
- }
-
- $scope.datasource.getAggregators().then(function(aggs) {
- $scope.aggregators = aggs;
- });
- };
-
- $scope.targetBlur = function() {
- $scope.target.errors = validateTarget($scope.target);
-
- // this does not work so good
- if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
- $scope.oldTarget = angular.copy($scope.target);
- $scope.get_data();
- }
- };
-
- $scope.getTextValues = function(metricFindResult) {
- return _.map(metricFindResult, function(value) { return value.text; });
- };
-
- $scope.suggestMetrics = function(query, callback) {
- $scope.datasource.metricFindQuery('metrics(' + query + ')')
- .then($scope.getTextValues)
- .then(callback);
- };
-
- $scope.suggestTagKeys = function(query, callback) {
- $scope.datasource.metricFindQuery('suggest_tagk(' + query + ')')
- .then($scope.getTextValues)
- .then(callback);
- };
-
- $scope.suggestTagValues = function(query, callback) {
- $scope.datasource.metricFindQuery('suggest_tagv(' + query + ')')
- .then($scope.getTextValues)
- .then(callback);
- };
-
- $scope.addTag = function() {
- if (!$scope.addTagMode) {
- $scope.addTagMode = true;
- return;
- }
-
- if (!$scope.target.tags) {
- $scope.target.tags = {};
- }
-
- $scope.target.errors = validateTarget($scope.target);
-
- if (!$scope.target.errors.tags) {
- $scope.target.tags[$scope.target.currentTagKey] = $scope.target.currentTagValue;
- $scope.target.currentTagKey = '';
- $scope.target.currentTagValue = '';
- $scope.targetBlur();
- }
-
- $scope.addTagMode = false;
- };
-
- $scope.removeTag = function(key) {
- delete $scope.target.tags[key];
- $scope.targetBlur();
- };
-
- $scope.editTag = function(key, value) {
- $scope.removeTag(key);
- $scope.target.currentTagKey = key;
- $scope.target.currentTagValue = value;
- $scope.addTag();
- };
-
- function validateTarget(target) {
- var errs = {};
-
- if (target.shouldDownsample) {
- try {
- if (target.downsampleInterval) {
- kbn.describe_interval(target.downsampleInterval);
- } else {
- errs.downsampleInterval = "You must supply a downsample interval (e.g. '1m' or '1h').";
- }
- } catch(err) {
- errs.downsampleInterval = err.message;
- }
- }
-
- if (target.tags && _.has(target.tags, target.currentTagKey)) {
- errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
- }
-
- return errs;
- }
-
- $scope.init();
- });
-
-});
diff --git a/public/app/plugins/datasource/opentsdb/query_ctrl.ts b/public/app/plugins/datasource/opentsdb/query_ctrl.ts
new file mode 100644
index 00000000000..9ed1aab55ce
--- /dev/null
+++ b/public/app/plugins/datasource/opentsdb/query_ctrl.ts
@@ -0,0 +1,128 @@
+///
+
+import _ from 'lodash';
+import kbn from 'app/core/utils/kbn';
+import {QueryCtrl} from 'app/features/panel/panel';
+
+export class OpenTsQueryCtrl extends QueryCtrl {
+ static templateUrl = 'public/app/plugins/datasource/opentsdb/partials/query.editor.html';
+ aggregators: any;
+ fillPolicies: any;
+ aggregator: any;
+ downsampleInterval: any;
+ downsampleAggregator: any;
+ downsampleFillPolicy: any;
+ errors: any;
+ suggestMetrics: any;
+ suggestTagKeys: any;
+ suggestTagValues: any;
+ addTagMode: boolean;
+
+ constructor($scope, $injector) {
+ super($scope, $injector);
+
+ this.errors = this.validateTarget();
+ this.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];
+ this.fillPolicies = ['none', 'nan', 'null', 'zero'];
+
+ if (!this.target.aggregator) {
+ this.target.aggregator = 'sum';
+ }
+
+ if (!this.target.downsampleAggregator) {
+ this.target.downsampleAggregator = 'avg';
+ }
+
+ if (!this.target.downsampleFillPolicy) {
+ this.target.downsampleFillPolicy = 'none';
+ }
+
+ this.datasource.getAggregators().then(function(aggs) {
+ this.aggregators = aggs;
+ });
+
+ // needs to be defined here as it is called from typeahead
+ this.suggestMetrics = (query, callback) => {
+ this.datasource.metricFindQuery('metrics(' + query + ')')
+ .then(this.getTextValues)
+ .then(callback);
+ };
+
+ this.suggestTagKeys = (query, callback) => {
+ this.datasource.metricFindQuery('suggest_tagk(' + query + ')')
+ .then(this.getTextValues)
+ .then(callback);
+ };
+
+ this.suggestTagValues = (query, callback) => {
+ this.datasource.metricFindQuery('suggest_tagv(' + query + ')')
+ .then(this.getTextValues)
+ .then(callback);
+ };
+ }
+
+ targetBlur() {
+ this.errors = this.validateTarget();
+ this.refresh();
+ }
+
+ getTextValues(metricFindResult) {
+ return _.map(metricFindResult, function(value) { return value.text; });
+ }
+
+ addTag() {
+ if (!this.addTagMode) {
+ this.addTagMode = true;
+ return;
+ }
+
+ if (!this.target.tags) {
+ this.target.tags = {};
+ }
+
+ this.errors = this.validateTarget();
+
+ if (!this.errors.tags) {
+ this.target.tags[this.target.currentTagKey] = this.target.currentTagValue;
+ this.target.currentTagKey = '';
+ this.target.currentTagValue = '';
+ this.targetBlur();
+ }
+
+ this.addTagMode = false;
+ }
+
+ removeTag(key) {
+ delete this.target.tags[key];
+ this.targetBlur();
+ }
+
+ editTag(key, value) {
+ this.removeTag(key);
+ this.target.currentTagKey = key;
+ this.target.currentTagValue = value;
+ this.addTag();
+ }
+
+ validateTarget() {
+ var errs: any = {};
+
+ if (this.target.shouldDownsample) {
+ try {
+ if (this.target.downsampleInterval) {
+ kbn.describe_interval(this.target.downsampleInterval);
+ } else {
+ errs.downsampleInterval = "You must supply a downsample interval (e.g. '1m' or '1h').";
+ }
+ } catch (err) {
+ errs.downsampleInterval = err.message;
+ }
+ }
+
+ if (this.target.tags && _.has(this.target.tags, this.target.currentTagKey)) {
+ errs.tags = "Duplicate tag key '" + this.target.currentTagKey + "'.";
+ }
+
+ return errs;
+ }
+}
diff --git a/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts
index 6f8b8917588..b786a93f14c 100644
--- a/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts
+++ b/public/app/plugins/datasource/opentsdb/specs/datasource-specs.ts
@@ -1,6 +1,6 @@
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import helpers from 'test/specs/helpers';
-import Datasource from "../datasource";
+import {OpenTsDatasource} from "../datasource";
describe('opentsdb', function() {
var ctx = new helpers.ServiceTestContext();
@@ -14,7 +14,7 @@ describe('opentsdb', function() {
ctx.$q = $q;
ctx.$httpBackend = $httpBackend;
ctx.$rootScope = $rootScope;
- ctx.ds = $injector.instantiate(Datasource, {instanceSettings: instanceSettings});
+ ctx.ds = $injector.instantiate(OpenTsDatasource, {instanceSettings: instanceSettings});
}));
describe('When performing metricFindQuery', function() {