[AMBARI-24665] Migrating grafana plugin for 5.x use. (Prajwal Rao, Ishan Bhatt via Ishan Bhatt)
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.d.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.d.ts
new file mode 100644
index 0000000..33286c8
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.d.ts
@@ -0,0 +1,5 @@
+/// <reference path="../../../../../public/app/headers/common.d.ts" />
+export declare class AmbariMetricsConfigCtrl {
+    static templateUrl: string;
+    current: any;
+}
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js
new file mode 100644
index 0000000..84244ed
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js
@@ -0,0 +1,34 @@
+///<reference path="../../../headers/common.d.ts" />
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+System.register([], function(exports_1) {
+    var AmbariMetricsConfigCtrl;
+    return {
+        setters:[],
+        execute: function() {
+            AmbariMetricsConfigCtrl = (function () {
+                function AmbariMetricsConfigCtrl() {
+                }
+                AmbariMetricsConfigCtrl.templateUrl = 'partials/config.html';
+                return AmbariMetricsConfigCtrl;
+            })();
+            exports_1("AmbariMetricsConfigCtrl", AmbariMetricsConfigCtrl);
+        }
+    }
+});
+//# sourceMappingURL=config_ctrl.js.map
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js.map b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js.map
new file mode 100644
index 0000000..8c46be5
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"config_ctrl.js","sourceRoot":"","sources":["../../../../../public/app/plugins/datasource/ambari-metrics/config_ctrl.ts"],"names":["AmbariMetricsConfigCtrl","AmbariMetricsConfigCtrl.constructor"],"mappings":"AAAA,oDAAoD;AACpD;;;;;;;;;;;;;;;;GAgBG;;;;;;YAKH;gBAAAA;gBAGAC,CAACA;gBAFUD,mCAAWA,GAAGA,sBAAsBA,CAACA;gBAEhDA,8BAACA;YAADA,CAACA,AAHD,IAGC;YAHD,6DAGC,CAAA"}
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.ts
new file mode 100644
index 0000000..f851f04
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.ts
@@ -0,0 +1,26 @@
+///<reference path="../../../headers/common.d.ts" />
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import _ from 'lodash';
+
+export class AmbariMetricsConfigCtrl {
+    static templateUrl = 'partials/config.html';
+    current: any;
+}
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.d.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.d.ts
new file mode 100644
index 0000000..8bab98c
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.d.ts
@@ -0,0 +1,20 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+declare var AmbariMetricsDatasource: any;
+export {AmbariMetricsDatasource};
+
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
index e7cd850..e34a1af 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
@@ -16,1077 +16,1201 @@
  * limitations under the License.
  */
 define([
-      'angular',
-      'lodash',
-      'jquery',
-      './directives',
-      './queryCtrl'
-    ],
-    function (angular, _) {
-      'use strict';
+    'angular',
+    'lodash',
+    'jquery',
+    //'./directives',
+    './query_ctrl'
+  ],
+  function (angular, _) {
+    'use strict';
 
-      var module = angular.module('grafana.services');
 
-      module.factory('AmbariMetricsDatasource', function ($q, backendSrv, templateSrv) {
-        /**
-         * AMS Datasource Constructor
-         */
-        function AmbariMetricsDatasource(datasource) {
-          this.name = datasource.name;
-          this.url = datasource.url;
-          this.initMetricAppidMapping();
+    /**
+     * AMS Datasource Constructor
+     */
+    function AmbariMetricsDatasource(instanceSettings, $q, backendSrv, templateSrv) {
+      this.type = 'ambari-metrics';
+      this.name = instanceSettings.name;
+      this.url = instanceSettings.url;
+      this.withCredentials = instanceSettings.withCredentials;
+      this.basicAuth = instanceSettings.basicAuth;
+
+      var allMetrics = {};
+      var appIds = [];
+
+      /**
+       * AMS Datasource  Authentication
+       */
+      this.doAmbariRequest = function (options) {
+        if (this.basicAuth || this.withCredentials) {
+          options.withCredentials = true;
         }
-        var allMetrics = {};
-        var appIds = [];
+        if (this.basicAuth) {
+          options.headers = options.headers || {};
+          options.headers.Authorization = this.basicAuth;
+        }
 
-        //We get a list of components and their associated metrics.
-        AmbariMetricsDatasource.prototype.initMetricAppidMapping = function () {
-          return this.doAmbariRequest({ url: '/ws/v1/timeline/metrics/metadata' })
-            .then(function (items) {
-              items = items.data;
-              allMetrics = {};
-              appIds = [];
-              _.forEach(items, function (metric,app) {
-                metric.forEach(function (component) {
-                  if (!allMetrics[app]) {
-                    allMetrics[app] = [];
-                  }
-                  allMetrics[app].push(component.metricname);
-                });
+        options.url = this.url + options.url;
+        options.inspect = {type: 'ambarimetrics'};
+
+        return backendSrv.datasourceRequest(options);
+      };
+
+      //We get a list of components and their associated metrics.
+      this.initMetricAppidMapping = function () {
+        return this.doAmbariRequest({url: '/ws/v1/timeline/metrics/metadata'})
+          .then(function (items) {
+            items = items.data;
+            allMetrics = {};
+            appIds = [];
+            _.forEach(items, function (metric, app) {
+              metric.forEach(function (component) {
+                if (!allMetrics[app]) {
+                  allMetrics[app] = [];
+                }
+                allMetrics[app].push(component.metricname);
               });
-              //We remove a couple of components from the list that do not contain any
-              //pertinent metrics.
-              delete allMetrics["timeline_metric_store_watcher"];
-              delete allMetrics["amssmoketestfake"];
-              appIds = Object.keys(allMetrics);
             });
-        };
+            //We remove a couple of components from the list that do not contain any
+            //pertinent metrics.
+            delete allMetrics["timeline_metric_store_watcher"];
+            delete allMetrics["amssmoketestfake"];
+            appIds = Object.keys(allMetrics);
+          });
+      };
+      this.initMetricAppidMapping();
 
-        /**
-         * AMS Datasource  Authentication
-         */
-        AmbariMetricsDatasource.prototype.doAmbariRequest = function (options) {
-          if (this.basicAuth || this.withCredentials) {
-            options.withCredentials = true;
-          }
-          if (this.basicAuth) {
-            options.headers = options.headers || {};
-            options.headers.Authorization = this.basicAuth;
-          }
 
-          options.url = this.url + options.url;
-          options.inspect = {type: 'ambarimetrics'};
 
-          return backendSrv.datasourceRequest(options);
-        };
-
-        /**
-         * AMS Datasource  Query
-         */
-        AmbariMetricsDatasource.prototype.query = function (options) {
-          var emptyData = function (metric) {
-            var legend = metric.alias ? metric.alias : metric.metric;
-            return {
-              data: {
-                target: legend,
-                datapoints: []
-              }
-            };
+      /**
+       * AMS Datasource  Query
+       */
+      this.query = function (options) {
+        var emptyData = function (metric) {
+          var legend = metric.alias ? metric.alias : metric.metric;
+          return {
+            data: {
+              target: legend,
+              datapoints: []
+            }
           };
-          var self = this;
-          var getMetricsData = function (target) {
-            var alias = target.alias ? target.alias : target.metric;
-            if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "yarnqueues") {
-              alias = alias + ' on ' + target.qmetric; }
-            if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "kafka-topics") {
-            alias = alias + ' on ' + target.kbTopic; }
-            return function (res) {
-              res = res.data;
-              console.log('processing metric ' + target.metric);
-              if (!res.metrics[0] || target.hide) {
-                return $q.when(emptyData(target));
+        };
+        var self = this;
+        var getMetricsData = function (target) {
+          var alias = target.alias ? target.alias : target.metric;
+          if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "yarnqueues") {
+            alias = alias + ' on ' + target.qmetric;
+          }
+          if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "kafka-topics") {
+            alias = alias + ' on ' + target.kbTopic;
+          }
+          return function (res) {
+            res = res.data;
+            console.log('processing metric ' + target.metric);
+            if (!res.metrics[0] || target.hide) {
+              return $q.when(emptyData(target));
+            }
+            var series = [];
+            var metricData = res.metrics[0].metrics;
+            // Added hostname to legend for templated dashboards.
+            var hostLegend = res.metrics[0].hostname ? ' on ' + res.metrics[0].hostname : '';
+            var timeSeries = {};
+            timeSeries = {
+              target: alias + hostLegend,
+              datapoints: []
+            };
+            for (var k in metricData) {
+              if (metricData.hasOwnProperty(k)) {
+                timeSeries.datapoints.push([metricData[k], (k - k % 1000)]);
               }
-              var series = [];
-              var metricData = res.metrics[0].metrics;
-              // Added hostname to legend for templated dashboards.
-              var hostLegend = res.metrics[0].hostname ? ' on ' + res.metrics[0].hostname : '';
-              var timeSeries = {};
+            }
+            series.push(timeSeries);
+            return $q.when({data: series});
+          };
+        };
+        // To speed up querying on templatized dashboards.
+        var allHostMetricsData = function (target) {
+          var alias = target.alias ? target.alias : target.metric;
+          if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-users") {
+            alias = alias + ' for ' + target.hbUser;
+          }
+          // Aliases for Storm Topologies and components under a topology.
+          if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "topologies" &&
+            !templateSrv.variables[1]) {
+            alias = alias + ' on ' + target.sTopology;
+          }
+          if (!_.isEmpty(templateSrv.variables[1]) && templateSrv.variables[1].name === "component") {
+            alias = alias + ' on ' + target.sTopology + ' for ' + target.sComponent;
+          }
+
+          // Aliases for Druid Datasources.
+          if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "druidDataSources" &&
+            !templateSrv.variables[1]) {
+            alias = alias.replace('$druidDataSource', target.sDataSource);
+          }
+          return function (res) {
+            res = res.data;
+            console.log('processing metric ' + target.metric);
+            if (!res.metrics[0] || target.hide) {
+              return $q.when(emptyData(target));
+            }
+            var series = [];
+            var timeSeries = {};
+            var metricData = res.metrics;
+            _.map(metricData, function (data) {
+              var totalCountFlag = false;
+              var aliasSuffix = data.hostname ? ' on ' + data.hostname : '';
+              var op = '';
+              var user = '';
+              if (!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-tables") {
+                var tableName = "Tables.";
+                var tableSuffix = data.metricname.substring(data.metricname.indexOf(tableName) + tableName.length,
+                  data.metricname.lastIndexOf("_metric"));
+                aliasSuffix = ' on ' + tableSuffix;
+              }
+              if (templateSrv.variables[0].query === "callers") {
+                alias = data.metricname.substring(data.metricname.indexOf('(') + 1, data.metricname.indexOf(')'));
+              }
+              // Set legend and alias for HDFS - TopN dashboard
+              if (data.metricname.indexOf('dfs.NNTopUserOpCounts') === 0) {
+                var metricname_arr = data.metricname.split(".");
+                _.map(metricname_arr, function (segment) {
+                  if (segment.indexOf('op=') === 0) {
+                    var opKey = 'op=';
+                    op = segment.substring(segment.indexOf(opKey) + opKey.length);
+                  } else if (segment.indexOf('user=') === 0) {
+                    var userKey = 'user=';
+                    user = segment.substring(segment.indexOf(userKey) + userKey.length);
+                  }
+                });
+                // Check if metric is TotalCount
+                if (data.metricname.indexOf('TotalCount') > 0) {
+                  totalCountFlag = true;
+                  if (op !== '*') {
+                    alias = op;
+                  } else {
+                    alias = 'Total Count';
+                  }
+                } else if (op !== '*') {
+                  alias = op + ' by ' + user;
+                } else {
+                  alias = user;
+                }
+                aliasSuffix = '';
+              }
+              if (data.appid.indexOf('ambari_server') === 0) {
+                alias = data.metricname;
+                aliasSuffix = '';
+              }
               timeSeries = {
-                target: alias + hostLegend,
+                target: alias + aliasSuffix,
                 datapoints: []
               };
-              for (var k in metricData){
-                if (metricData.hasOwnProperty(k)) {
-                  timeSeries.datapoints.push([metricData[k], (k - k % 1000)]);
+              for (var k in data.metrics) {
+                if (data.metrics.hasOwnProperty(k)) {
+                  timeSeries.datapoints.push([data.metrics[k], (k - k % 1000)]);
                 }
               }
-              series.push(timeSeries);
-              return $q.when({data: series});
-            };
-          };
-          // To speed up querying on templatized dashboards.
-          var allHostMetricsData = function (target) {
-            var alias = target.alias ? target.alias : target.metric;
-            if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-users") {
-            alias = alias + ' for ' + target.hbUser; }
-            // Aliases for Storm Topologies and components under a topology.
-            if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "topologies" &&
-            !templateSrv.variables[1]) {
-              alias = alias + ' on ' + target.sTopology;
-            }
-            if(!_.isEmpty(templateSrv.variables[1]) && templateSrv.variables[1].name === "component") {
-              alias = alias + ' on ' + target.sTopology + ' for ' + target.sComponent;
-            }
-
-            // Aliases for Druid Datasources.
-            if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "druidDataSources" &&
-                        !templateSrv.variables[1]) {
-              alias = alias.replace('$druidDataSource', target.sDataSource);
-            }
-            return function (res) {
-              res = res.data;
-              console.log('processing metric ' + target.metric);
-              if (!res.metrics[0] || target.hide) {
-                return $q.when(emptyData(target));
+              if ((user !== '*') || (totalCountFlag)) {
+                series.push(timeSeries);
               }
-              var series = [];
-              var timeSeries = {};
-              var metricData = res.metrics;
-              _.map(metricData, function (data) {
-                var totalCountFlag = false;
-                var aliasSuffix = data.hostname ? ' on ' + data.hostname : '';
-                var op = '';
-                var user = '';
-                if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-tables") {
-                  var tableName = "Tables.";
-                  var tableSuffix = data.metricname.substring(data.metricname.indexOf(tableName) + tableName.length,
-                  data.metricname.lastIndexOf("_metric"));
-                  aliasSuffix = ' on ' + tableSuffix;
-                }
-                if(templateSrv.variables[0].query === "callers") {
-                  alias = data.metricname.substring(data.metricname.indexOf('(')+1, data.metricname.indexOf(')'));
-                }
-                // Set legend and alias for HDFS - TopN dashboard
-                if(data.metricname.indexOf('dfs.NNTopUserOpCounts') === 0) {
-                  var metricname_arr = data.metricname.split(".");
-                  _.map(metricname_arr, function (segment) {
-                    if(segment.indexOf('op=') === 0) {
-                      var opKey = 'op=';
-                      op = segment.substring(segment.indexOf(opKey) + opKey.length);
-                    } else if(segment.indexOf('user=') === 0) {
-                      var userKey = 'user=';
-                      user = segment.substring(segment.indexOf(userKey) + userKey.length);
-                    }
-                  });
-                  // Check if metric is TotalCount
-                  if(data.metricname.indexOf('TotalCount') > 0) {
-                    totalCountFlag = true;
-                    if (op !== '*') {
-                      alias = op;
-                    } else {
-                      alias = 'Total Count';
-                    }
-                  } else if (op !== '*') {
-                    alias = op + ' by ' + user;
-                  } else {
-                    alias = user;
-                  }
-                  aliasSuffix = '';
-                }
-                if (data.appid.indexOf('ambari_server') === 0) {
-                  alias = data.metricname;
-                  aliasSuffix = '';
-                }
-                timeSeries = {
-                  target: alias + aliasSuffix,
-                  datapoints: []
-                };
-                for (var k in data.metrics){
-                  if (data.metrics.hasOwnProperty(k)) {
-                    timeSeries.datapoints.push([data.metrics[k], (k - k % 1000)]);
-                  }
-                }
-                if( (user !== '*') || (totalCountFlag) ) {
-                  series.push(timeSeries);
-                }
-              });
-              return $q.when({data: series});
-            };
+            });
+            return $q.when({data: series});
           };
-          var getHostAppIdData = function(target) {
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision=' 
+        };
+        var getHostAppIdData = function (target) {
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var instanceId = typeof target.cluster == 'undefined'  ? '' : '&instanceId=' + target.cluster;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform +
+          var instanceId = typeof target.cluster == 'undefined' ? '' : '&instanceId=' + target.cluster;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform +
             metricAggregator + "&hostname=" + target.hosts + '&appId=' + target.app + instanceId + '&startTime=' + from +
-            '&endTime=' + to + precision + seriesAggregator }).then(
-              getMetricsData(target)
-            );
-          };
-          //Check if it's a templated dashboard.
-          var templatedClusters = templateSrv.variables.filter(function(o) { return o.name === "cluster"});
-          var templatedCluster = (_.isEmpty(templatedClusters)) ? '' : templatedClusters[0].options.filter(function(cluster)
-            { return cluster.selected; }).map(function(clusterName) { return clusterName.value; });
+            '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            getMetricsData(target)
+          );
+        };
+        //Check if it's a templated dashboard.
+        var templatedClusters = templateSrv.variables.filter(function (o) {
+          return o.name === "cluster"
+        });
+        var templatedCluster = (_.isEmpty(templatedClusters)) ? '' : templatedClusters[0].options.filter(function (cluster) {
+          return cluster.selected;
+        }).map(function (clusterName) {
+          return clusterName.value;
+        });
 
-          var templatedHosts = templateSrv.variables.filter(function(o) { return o.name === "hosts"});
-          var templatedHost = (_.isEmpty(templatedHosts)) ? '' : templatedHosts[0].options.filter(function(host)
-            { return host.selected; }).map(function(hostName) { return hostName.value; });
+        var templatedHosts = templateSrv.variables.filter(function (o) {
+          return o.name === "hosts"
+        });
+        var templatedHost = (_.isEmpty(templatedHosts)) ? '' : templatedHosts[0].options.filter(function (host) {
+          return host.selected;
+        }).map(function (hostName) {
+          return hostName.value;
+        });
 
-          var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function(variable)
-            { return variable.name === "components"});
-          var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
+        var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function (variable) {
+          return variable.name === "components"
+        });
+        var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
 
-          var getServiceAppIdData = function(target) {
-            var tCluster = (_.isEmpty(templateSrv.variables))? templatedCluster : '';
-            var instanceId = typeof tCluster == 'undefined'  ? '' : '&instanceId=' + tCluster;
-            var tHost = (_.isEmpty(templateSrv.variables)) ? templatedHost : target.templatedHost;
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+        var getServiceAppIdData = function (target) {
+          var tCluster = (_.isEmpty(templateSrv.variables)) ? templatedCluster : '';
+          var instanceId = typeof tCluster == 'undefined' ? '' : '&instanceId=' + tCluster;
+          var tHost = (_.isEmpty(templateSrv.variables)) ? templatedHost : target.templatedHost;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
-              + metricAggregator + '&hostname=' + tHost + '&appId=' + target.app + instanceId + '&startTime=' + from +
-              '&endTime=' + to + precision + seriesAggregator }).then(
-              getMetricsData(target)
-            );
-          };
-          // To speed up querying on templatized dashboards.
-          var getAllHostData = function(target) {
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
+            + metricAggregator + '&hostname=' + tHost + '&appId=' + target.app + instanceId + '&startTime=' + from +
+            '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            getMetricsData(target)
+          );
+        };
+        // To speed up querying on templatized dashboards.
+        var getAllHostData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var topN = ""; var isBottomN = "";
-            if (!_.isEmpty(templateSrv.variables.filter(function(o) { return o.name === "instances";}))) {
-              var metricTopN = _.filter(templateSrv.variables, function (o) { return o.name === "instances"; });
-              var metricTopAgg = _.filter(templateSrv.variables, function (o) { return o.name === "topagg"; });
-              isBottomN = templateSrv.variables.filter(function(o) { return o.name === "orientation";})[0].current.value
-              === "bottom" ? true : false;
-              topN = '&topN=' + metricTopN[0].current.value  +'&topNFunction=' + metricTopAgg[0].current.value  + '&isBottomN='+ isBottomN;
-            }
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            var templatedComponent = (_.isEmpty(tComponent)) ? target.app : tComponent;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
-              + metricAggregator + '&hostname=' + target.templatedHost + '&appId=' + templatedComponent + instanceId
-              + '&startTime=' + from + '&endTime=' + to + precision + topN + seriesAggregator }).then(
-              allHostMetricsData(target)
-            );
-          };
-          var getYarnAppIdData = function(target) {
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var topN = "";
+          var isBottomN = "";
+          if (!_.isEmpty(templateSrv.variables.filter(function (o) {
+            return o.name === "instances";
+          }))) {
+            var metricTopN = _.filter(templateSrv.variables, function (o) {
+              return o.name === "instances";
+            });
+            var metricTopAgg = _.filter(templateSrv.variables, function (o) {
+              return o.name === "topagg";
+            });
+            isBottomN = templateSrv.variables.filter(function (o) {
+              return o.name === "orientation";
+            })[0].current.value
+            === "bottom" ? true : false;
+            topN = '&topN=' + metricTopN[0].current.value + '&topNFunction=' + metricTopAgg[0].current.value + '&isBottomN=' + isBottomN;
+          }
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          var templatedComponent = (_.isEmpty(tComponent)) ? target.app : tComponent;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
+            + metricAggregator + '&hostname=' + target.templatedHost + '&appId=' + templatedComponent + instanceId
+            + '&startTime=' + from + '&endTime=' + to + precision + topN + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
+        var getYarnAppIdData = function (target) {
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + encodeURIComponent(target.queue) + metricTransform
-              + metricAggregator + '&appId=resourcemanager' + instanceId + '&startTime=' + from +
-              '&endTime=' + to + precision + seriesAggregator }).then(
-              getMetricsData(target)
-            );
-          };
-          var getHbaseAppIdData = function(target) {
-              var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-              var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + encodeURIComponent(target.queue) + metricTransform
+            + metricAggregator + '&appId=resourcemanager' + instanceId + '&startTime=' + from +
+            '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            getMetricsData(target)
+          );
+        };
+        var getHbaseAppIdData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.hbMetric + instanceId + '&appId=hbase&startTime='
-            + from + '&endTime=' + to + precision + seriesAggregator }).then(
-              allHostMetricsData(target)
-            );
-          };
-          
-          var getKafkaAppIdData = function(target) {
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.hbMetric + instanceId + '&appId=hbase&startTime='
+            + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
+
+        var getKafkaAppIdData = function (target) {
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.kbMetric + metricTransform + instanceId
-              + metricAggregator + '&appId=kafka_broker&startTime=' + from +
-              '&endTime=' + to + precision + seriesAggregator }).then(
-              getMetricsData(target)
-            );
-          };
-          var getNnAppIdData = function(target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.kbMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=kafka_broker&startTime=' + from +
+            '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            getMetricsData(target)
+          );
+        };
+        var getNnAppIdData = function (target) {
 
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.nnMetric + metricTransform + instanceId
-            + metricAggregator + '&appId=namenode&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
-              allHostMetricsData(target)
-            );
-          };
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.nnMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=namenode&startTime=' + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
 
-          // Storm Topology calls.
-          var getStormData = function(target) {
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+        // Storm Topology calls.
+        var getStormData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.sTopoMetric + metricTransform + instanceId
-                + metricAggregator + '&appId=nimbus&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
-                allHostMetricsData(target)
-            );
-          };
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.sTopoMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=nimbus&startTime=' + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
 
-            // Infra Solr Calls
-          var getSolrCoreData = function(target) {
-              var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-              var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
-                  + target.precision;
-              var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-              var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-              var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-              return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.sCoreMetric + metricTransform + instanceId
-              + metricAggregator + '&appId=ambari-infra-solr&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
-                  allHostMetricsData(target)
-              );
-          };
-
-          var getSolrCollectionData = function(target) {
-              var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-              var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
-                  + target.precision;
-              var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-              var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-              var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-              return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.sCollectionMetric + metricTransform + instanceId
-              + metricAggregator + '&appId=ambari-infra-solr&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
-                  allHostMetricsData(target)
-              );
-          };
-
-          // Druid calls.
-          var getDruidData = function(target) {
-            var instanceId = typeof target.templatedCluster == 'undefined'  ? '' : '&instanceId=' + target.templatedCluster;
-            var precision = target.precision === 'default' || typeof target.precision == 'undefined'  ? '' : '&precision='
+        // Infra Solr Calls
+        var getSolrCoreData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
             + target.precision;
-            var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
-            var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-            var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
-            return self.doAmbariRequest({ url: '/ws/v1/timeline/metrics?metricNames=' + target.sDataSourceMetric + metricTransform + instanceId
-                          + metricAggregator + '&appId=druid&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
-                          allHostMetricsData(target)
-            );
-          };
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.sCoreMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=ambari-infra-solr&startTime=' + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
 
-          // Time Ranges
-          var from = Math.floor(options.range.from.valueOf() / 1000);
-          var to = Math.floor(options.range.to.valueOf() / 1000);
+        var getSolrCollectionData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
+            + target.precision;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.sCollectionMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=ambari-infra-solr&startTime=' + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
 
-          var metricsPromises = [];
-          if (!_.isEmpty(templateSrv.variables)) {
-            // YARN Queues Dashboard
-            if (templateSrv.variables[0].query === "yarnqueues") {
-              var allQueues = templateSrv.variables.filter(function(variable) { return variable.query === "yarnqueues";});
-              var selectedQs = (_.isEmpty(allQueues)) ? "" : allQueues[0].options.filter(function(q)
-              { return q.selected; }).map(function(qName) { return qName.value; });
-              // All Queues
-              if (!_.isEmpty(_.find(selectedQs, function (wildcard) { return wildcard === "*"; })))  {
-                var allQueue = allQueues[0].options.filter(function(q) {
-                  return q.text !== "All"; }).map(function(queue) { return queue.value; });
-                _.forEach(allQueue, function(processQueue) {
-                  metricsPromises.push(_.map(options.targets, function(target) {
-                    target.qmetric = processQueue;
-                    target.queue = target.metric.replace('root', target.qmetric);
-                    return getYarnAppIdData(target);
-                  }));
-                });
-              } else {
-                // All selected queues.
-                _.forEach(selectedQs, function(processQueue) {
-                  metricsPromises.push(_.map(options.targets, function(target) {
-                    target.qmetric = processQueue;
-                    target.queue = target.metric.replace('root', target.qmetric);
-                    return getYarnAppIdData(target);
-                  }));
-                });
-              }
-            }
-            // Templatized Dashboard for per-user metrics in HBase.
-            if (templateSrv.variables[0].query === "hbase-users") {
-              var allUsers = templateSrv.variables.filter(function(variable) { return variable.query === "hbase-users";});
-              var selectedUsers = (_.isEmpty(allUsers)) ? "" : allUsers[0].options.filter(function(user)
-              { return user.selected; }).map(function(uName) { return uName.value; });
-              selectedUsers = templateSrv._values.Users.lastIndexOf('}') > 0 ? templateSrv._values.Users.slice(1,-1) :
-                templateSrv._values.Users;
-              var selectedUser = selectedUsers.split(',');
-              _.forEach(selectedUser, function(processUser) {
-                  metricsPromises.push(_.map(options.targets, function(target) {
-                    target.hbUser = processUser;
-                    var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-                    target.hbMetric = target.metric.replace('*', target.hbUser) + metricTransform +'._' +  target.aggregator;
-                    return getHbaseAppIdData(target);
-                  }));
-                });
-            }
-            // Templatized Dashboard for per-table metrics in HBase.
-            if (templateSrv.variables[0].query === "hbase-tables") {
-              var splitTables = [];
-              var allTables = templateSrv._values.Tables.lastIndexOf('}') > 0 ? templateSrv._values.Tables.slice(1,-1) :
-                templateSrv._values.Tables;
-              var allTable = allTables.split(',');
-              while (allTable.length > 0) {
-                splitTables.push(allTable.splice(0,20));
-              }
-              _.forEach(splitTables, function(table) {
-                metricsPromises.push(_.map(options.targets, function(target) {
-                  var hbMetric = [];
-                  _.map(table, function(tableMetric) { hbMetric.push(target.metric.replace('*', tableMetric)); });
-                  var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform; 
-                  hbMetric = _.map(hbMetric, function(tbl) { return tbl + metricTransform +'._' +  target.aggregator; });
-                  target.hbMetric = _.flatten(hbMetric).join(',');
-                  return getHbaseAppIdData(target);
+        // Druid calls.
+        var getDruidData = function (target) {
+          var instanceId = typeof target.templatedCluster == 'undefined' ? '' : '&instanceId=' + target.templatedCluster;
+          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
+            + target.precision;
+          var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
+          var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+          var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
+          return self.doAmbariRequest({
+            url: '/ws/v1/timeline/metrics?metricNames=' + target.sDataSourceMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=druid&startTime=' + from + '&endTime=' + to + precision + seriesAggregator
+          }).then(
+            allHostMetricsData(target)
+          );
+        };
+
+        // Time Ranges
+        var from = Math.floor(options.range.from.valueOf() / 1000);
+        var to = Math.floor(options.range.to.valueOf() / 1000);
+
+        var metricsPromises = [];
+        if (!_.isEmpty(templateSrv.variables)) {
+          // YARN Queues Dashboard
+          if (templateSrv.variables[0].query === "yarnqueues") {
+            var allQueues = templateSrv.variables.filter(function (variable) {
+              return variable.query === "yarnqueues";
+            });
+            var selectedQs = (_.isEmpty(allQueues)) ? "" : allQueues[0].options.filter(function (q) {
+              return q.selected;
+            }).map(function (qName) {
+              return qName.value;
+            });
+            // All Queues
+            if (!_.isEmpty(_.find(selectedQs, function (wildcard) {
+              return wildcard === "*";
+            }))) {
+              var allQueue = allQueues[0].options.filter(function (q) {
+                return q.text !== "All";
+              }).map(function (queue) {
+                return queue.value;
+              });
+              _.forEach(allQueue, function (processQueue) {
+                metricsPromises.push(_.map(options.targets, function (target) {
+                  target.qmetric = processQueue;
+                  target.queue = target.metric.replace('root', target.qmetric);
+                  return getYarnAppIdData(target);
+                }));
+              });
+            } else {
+              // All selected queues.
+              _.forEach(selectedQs, function (processQueue) {
+                metricsPromises.push(_.map(options.targets, function (target) {
+                  target.qmetric = processQueue;
+                  target.queue = target.metric.replace('root', target.qmetric);
+                  return getYarnAppIdData(target);
                 }));
               });
             }
-            // Templatized Dashboard for per-topic metrics in Kafka.
-            if (templateSrv.variables[0].query === "kafka-topics") {
-              var allTopics = templateSrv.variables.filter(function(variable) { return variable.query === "kafka-topics";});
-              var selectedTopics = (_.isEmpty(allTopics)) ? "" : allTopics[0].options.filter(function(topic)
-              { return topic.selected; }).map(function(topicName) { return topicName.value; });
-              selectedTopics = templateSrv._values.Topics.lastIndexOf('}') > 0 ? templateSrv._values.Topics.slice(1,-1) :
-                templateSrv._values.Topics;
-              var selectedTopic = selectedTopics.split(',');  
-              _.forEach(selectedTopic, function(processTopic) {
-                metricsPromises.push(_.map(options.targets, function(target) {
-                  target.kbTopic = processTopic;
-                  target.kbMetric = target.metric.replace('*', target.kbTopic);
-                  return getKafkaAppIdData(target);
-                }));
-              });
-            }
-            //Templatized Dashboard for Call Queues
-            if (templateSrv.variables[0].query === "callers") {
-              var allCallers = templateSrv.variables.filter(function(variable) { return variable.query === "callers";});
-              var selectedCallers = (_.isEmpty(allCallers)) ? "" : allCallers[0].options.filter(function(user)
-              { return user.selected; }).map(function(callerName) { return callerName.value; });
-              selectedCallers = templateSrv._values.Callers.lastIndexOf('}') > 0 ? templateSrv._values.Callers.slice(1,-1) :
-                templateSrv._values.Callers;
-              var selectedCaller = selectedCallers.split(',');
-              _.forEach(selectedCaller, function(processCaller) {
-                  metricsPromises.push(_.map(options.targets, function(target) {
-                    target.nnCaller = processCaller;
-                    target.nnMetric = target.metric.replace('*', target.nnCaller);
-                    return getNnAppIdData(target);
-                  }));
-              });
-            }
-
-            //Templatized Dashboard for Infra Solr Cores
-            if (templateSrv.variables[0].query === "infra_solr_core") {
-                var allCores = templateSrv.variables.filter(function(variable) { return variable.query === "infra_solr_core";});
-                var selectedCores = (_.isEmpty(allCores)) ? "" : allCores[0].options.filter(function(core)
-                { return core.selected; }).map(function(coreName) { return coreName.value; });
-                selectedCores = templateSrv._values.Cores.lastIndexOf('}') > 0 ? templateSrv._values.Cores.slice(1,-1) :
-                    templateSrv._values.Cores;
-                var selectedCore= selectedCores.split(',');
-                _.forEach(selectedCore, function(processCore) {
-                    metricsPromises.push(_.map(options.targets, function(target) {
-                        target.sCore = processCore;
-                        target.sCoreMetric = target.metric.replace('*', target.sCore);
-                        return getSolrCoreData(target);
-                    }));
-                });
-            }
-
-            //Templatized Dashboard for Infra Solr Collections
-            if (templateSrv.variables[0].query === "infra_solr_collection") {
-                var allCollections = templateSrv.variables.filter(function(variable) { return variable.query === "infra_solr_collection";});
-                var selectedCollections = (_.isEmpty(allCollections)) ? "" : allCollections[0].options.filter(function(collection)
-                { return collection.selected; }).map(function(collectionsName) { return collectionsName.value; });
-                selectedCollections = templateSrv._values.Collections.lastIndexOf('}') > 0 ? templateSrv._values.Collections.slice(1,-1) :
-                    templateSrv._values.Collections;
-                var selectedCollection= selectedCollections.split(',');
-                _.forEach(selectedCollection, function(processCollection) {
-                    metricsPromises.push(_.map(options.targets, function(target) {
-                        target.sCollection = processCollection;
-                        target.sCollectionMetric = target.metric.replace('*', target.sCollection);
-                        return getSolrCollectionData(target);
-                    }));
-                });
-            }
-
-            //Templatized Dashboard for Storm Topologies
-            if (templateSrv.variables[0].query === "topologies" && !templateSrv.variables[1]) {
-              var allTopologies = templateSrv.variables.filter(function(variable) { return variable.query === "topologies";});
-              var selectedTopologies = (_.isEmpty(allTopologies)) ? "" : allTopologies[0].options.filter(function(topo)
-              { return topo.selected; }).map(function(topoName) { return topoName.value; });
-              selectedTopologies = templateSrv._values.topologies.lastIndexOf('}') > 0 ? templateSrv._values.topologies.slice(1,-1) :
-                  templateSrv._values.topologies;
-              var selectedTopology= selectedTopologies.split(',');
-              _.forEach(selectedTopology, function(processTopology) {
-                metricsPromises.push(_.map(options.targets, function(target) {
-                  target.sTopology = processTopology;
-                  target.sTopoMetric = target.metric.replace('*', target.sTopology);
-                  return getStormData(target);
-                }));
-              });
-            }
-
-            //Templatized Dashboards for Storm Components
-            if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
-                templateSrv.variables[1].name === "component") {
-              var selectedTopology = templateSrv._values.topologies;
-              var selectedComponent = templateSrv._values.component;
-              metricsPromises.push(_.map(options.targets, function(target) {
-                target.sTopology = selectedTopology;
-                target.sComponent = selectedComponent;
-                target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sComponent);
-                  return getStormData(target);
+          }
+          // Templatized Dashboard for per-user metrics in HBase.
+          if (templateSrv.variables[0].query === "hbase-users") {
+            var allUsers = templateSrv.variables.filter(function (variable) {
+              return variable.query === "hbase-users";
+            });
+            var selectedUsers = (_.isEmpty(allUsers)) ? "" : allUsers[0].options.filter(function (user) {
+              return user.selected;
+            }).map(function (uName) {
+              return uName.value;
+            });
+            selectedUsers = templateSrv._values.Users.lastIndexOf('}') > 0 ? templateSrv._values.Users.slice(1, -1) :
+              templateSrv._values.Users;
+            var selectedUser = selectedUsers.split(',');
+            _.forEach(selectedUser, function (processUser) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.hbUser = processUser;
+                var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+                target.hbMetric = target.metric.replace('*', target.hbUser) + metricTransform + '._' + target.aggregator;
+                return getHbaseAppIdData(target);
               }));
+            });
+          }
+          // Templatized Dashboard for per-table metrics in HBase.
+          if (templateSrv.variables[0].query === "hbase-tables") {
+            var splitTables = [];
+            var allTables = templateSrv._values.Tables.lastIndexOf('}') > 0 ? templateSrv._values.Tables.slice(1, -1) :
+              templateSrv._values.Tables;
+            var allTable = allTables.split(',');
+            while (allTable.length > 0) {
+              splitTables.push(allTable.splice(0, 20));
             }
+            _.forEach(splitTables, function (table) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                var hbMetric = [];
+                _.map(table, function (tableMetric) {
+                  hbMetric.push(target.metric.replace('*', tableMetric));
+                });
+                var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
+                hbMetric = _.map(hbMetric, function (tbl) {
+                  return tbl + metricTransform + '._' + target.aggregator;
+                });
+                target.hbMetric = _.flatten(hbMetric).join(',');
+                return getHbaseAppIdData(target);
+              }));
+            });
+          }
+          // Templatized Dashboard for per-topic metrics in Kafka.
+          if (templateSrv.variables[0].query === "kafka-topics") {
+            var allTopics = templateSrv.variables.filter(function (variable) {
+              return variable.query === "kafka-topics";
+            });
+            var selectedTopics = (_.isEmpty(allTopics)) ? "" : allTopics[0].options.filter(function (topic) {
+              return topic.selected;
+            }).map(function (topicName) {
+              return topicName.value;
+            });
+            selectedTopics = templateSrv._values.Topics.lastIndexOf('}') > 0 ? templateSrv._values.Topics.slice(1, -1) :
+              templateSrv._values.Topics;
+            var selectedTopic = selectedTopics.split(',');
+            _.forEach(selectedTopic, function (processTopic) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.kbTopic = processTopic;
+                target.kbMetric = target.metric.replace('*', target.kbTopic);
+                return getKafkaAppIdData(target);
+              }));
+            });
+          }
+          //Templatized Dashboard for Call Queues
+          if (templateSrv.variables[0].query === "callers") {
+            var allCallers = templateSrv.variables.filter(function (variable) {
+              return variable.query === "callers";
+            });
+            var selectedCallers = (_.isEmpty(allCallers)) ? "" : allCallers[0].options.filter(function (user) {
+              return user.selected;
+            }).map(function (callerName) {
+              return callerName.value;
+            });
+            selectedCallers = templateSrv._values.Callers.lastIndexOf('}') > 0 ? templateSrv._values.Callers.slice(1, -1) :
+              templateSrv._values.Callers;
+            var selectedCaller = selectedCallers.split(',');
+            _.forEach(selectedCaller, function (processCaller) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.nnCaller = processCaller;
+                target.nnMetric = target.metric.replace('*', target.nnCaller);
+                return getNnAppIdData(target);
+              }));
+            });
+          }
 
-            //Templatized Dashboard for Storm Kafka Offset
-            if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
-                templateSrv.variables[1].name === "topic") {
-              var selectedTopology = templateSrv._values.topologies;
-              var selectedTopic = templateSrv._values.topic;
-              metricsPromises.push(_.map(options.targets, function(target) {
-                target.sTopology = selectedTopology;
-                target.sTopic = selectedTopic;
-                target.sPartition = options.scopedVars.partition.value;
-                target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sTopic)
-                    .replace('*', target.sPartition);
+          //Templatized Dashboard for Infra Solr Cores
+          if (templateSrv.variables[0].query === "infra_solr_core") {
+            var allCores = templateSrv.variables.filter(function (variable) {
+              return variable.query === "infra_solr_core";
+            });
+            var selectedCores = (_.isEmpty(allCores)) ? "" : allCores[0].options.filter(function (core) {
+              return core.selected;
+            }).map(function (coreName) {
+              return coreName.value;
+            });
+            selectedCores = templateSrv._values.Cores.lastIndexOf('}') > 0 ? templateSrv._values.Cores.slice(1, -1) :
+              templateSrv._values.Cores;
+            var selectedCore = selectedCores.split(',');
+            _.forEach(selectedCore, function (processCore) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.sCore = processCore;
+                target.sCoreMetric = target.metric.replace('*', target.sCore);
+                return getSolrCoreData(target);
+              }));
+            });
+          }
+
+          //Templatized Dashboard for Infra Solr Collections
+          if (templateSrv.variables[0].query === "infra_solr_collection") {
+            var allCollections = templateSrv.variables.filter(function (variable) {
+              return variable.query === "infra_solr_collection";
+            });
+            var selectedCollections = (_.isEmpty(allCollections)) ? "" : allCollections[0].options.filter(function (collection) {
+              return collection.selected;
+            }).map(function (collectionsName) {
+              return collectionsName.value;
+            });
+            selectedCollections = templateSrv._values.Collections.lastIndexOf('}') > 0 ? templateSrv._values.Collections.slice(1, -1) :
+              templateSrv._values.Collections;
+            var selectedCollection = selectedCollections.split(',');
+            _.forEach(selectedCollection, function (processCollection) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.sCollection = processCollection;
+                target.sCollectionMetric = target.metric.replace('*', target.sCollection);
+                return getSolrCollectionData(target);
+              }));
+            });
+          }
+
+          //Templatized Dashboard for Storm Topologies
+          if (templateSrv.variables[0].query === "topologies" && !templateSrv.variables[1]) {
+            var allTopologies = templateSrv.variables.filter(function (variable) {
+              return variable.query === "topologies";
+            });
+            var selectedTopologies = (_.isEmpty(allTopologies)) ? "" : allTopologies[0].options.filter(function (topo) {
+              return topo.selected;
+            }).map(function (topoName) {
+              return topoName.value;
+            });
+            selectedTopologies = templateSrv._values.topologies.lastIndexOf('}') > 0 ? templateSrv._values.topologies.slice(1, -1) :
+              templateSrv._values.topologies;
+            var selectedTopology = selectedTopologies.split(',');
+            _.forEach(selectedTopology, function (processTopology) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.sTopology = processTopology;
+                target.sTopoMetric = target.metric.replace('*', target.sTopology);
                 return getStormData(target);
               }));
-            }
+            });
+          }
 
-            //Templatized Dashboards for Druid
-            if (templateSrv.variables[0].query === "druidDataSources" && !templateSrv.variables[1]) {
-              var allDataSources = templateSrv.variables.filter(function(variable) { return variable.query === "druidDataSources";});
-              var selectedDataSources = (_.isEmpty(allDataSources)) ? "" : allDataSources[0].options.filter(function(dataSource)
-                            { return dataSource.selected; }).map(function(dataSourceName) { return dataSourceName.value; });
-               selectedDataSources = templateSrv._values.druidDataSources.lastIndexOf('}') > 0 ? templateSrv._values.druidDataSources.slice(1,-1) :
-                                              templateSrv._values.druidDataSources;
-              var selectedDataSource = selectedDataSources.split(',');
-              _.forEach(selectedDataSource, function(processDataSource) {
-                metricsPromises.push(_.map(options.targets, function(target) {
-                  target.sDataSource = processDataSource;
-                  target.sDataSourceMetric = target.metric.replace('*', target.sDataSource);
-                  return getDruidData(target);
-                }));
-              });
-            }
-            // To speed up querying on templatized dashboards.
-              var indexOfHosts = -1;
-              for (var i = 0; i < templateSrv.variables.length; i++) {
-                  if (templateSrv.variables[i].name == 'hosts') {
-                      indexOfHosts = i;
-                  }
-              }
-              if (indexOfHosts >= 0) {
-              var allHosts = templateSrv._values.hosts.lastIndexOf('}') > 0 ? templateSrv._values.hosts.slice(1,-1) :
-              templateSrv._values.hosts;
-              allHosts = templateSrv._texts.hosts === "All" ? '%' : allHosts;
-              metricsPromises.push(_.map(options.targets, function(target) {
-                  target.templatedHost = allHosts? allHosts : '';
-                  target.templatedCluster = templatedCluster;
-                  return getAllHostData(target);
+          //Templatized Dashboards for Storm Components
+          if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
+            templateSrv.variables[1].name === "component") {
+            var selectedTopology = templateSrv._values.topologies;
+            var selectedComponent = templateSrv._values.component;
+            metricsPromises.push(_.map(options.targets, function (target) {
+              target.sTopology = selectedTopology;
+              target.sComponent = selectedComponent;
+              target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sComponent);
+              return getStormData(target);
+            }));
+          }
+
+          //Templatized Dashboard for Storm Kafka Offset
+          if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
+            templateSrv.variables[1].name === "topic") {
+            var selectedTopology = templateSrv._values.topologies;
+            var selectedTopic = templateSrv._values.topic;
+            metricsPromises.push(_.map(options.targets, function (target) {
+              target.sTopology = selectedTopology;
+              target.sTopic = selectedTopic;
+              target.sPartition = options.scopedVars.partition.value;
+              target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sTopic)
+                .replace('*', target.sPartition);
+              return getStormData(target);
+            }));
+          }
+
+          //Templatized Dashboards for Druid
+          if (templateSrv.variables[0].query === "druidDataSources" && !templateSrv.variables[1]) {
+            var allDataSources = templateSrv.variables.filter(function (variable) {
+              return variable.query === "druidDataSources";
+            });
+            var selectedDataSources = (_.isEmpty(allDataSources)) ? "" : allDataSources[0].options.filter(function (dataSource) {
+              return dataSource.selected;
+            }).map(function (dataSourceName) {
+              return dataSourceName.value;
+            });
+            selectedDataSources = templateSrv._values.druidDataSources.lastIndexOf('}') > 0 ? templateSrv._values.druidDataSources.slice(1, -1) :
+              templateSrv._values.druidDataSources;
+            var selectedDataSource = selectedDataSources.split(',');
+            _.forEach(selectedDataSource, function (processDataSource) {
+              metricsPromises.push(_.map(options.targets, function (target) {
+                target.sDataSource = processDataSource;
+                target.sDataSourceMetric = target.metric.replace('*', target.sDataSource);
+                return getDruidData(target);
               }));
+            });
+          }
+          // To speed up querying on templatized dashboards.
+          var indexOfHosts = -1;
+          for (var i = 0; i < templateSrv.variables.length; i++) {
+            if (templateSrv.variables[i].name == 'hosts') {
+              indexOfHosts = i;
             }
-            metricsPromises = _.flatten(metricsPromises);
-          } else {
-            // Non Templatized Dashboards
-            metricsPromises = _.map(options.targets, function(target) {
-              console.debug('target app=' + target.app + ',' +
-                'target metric=' + target.metric + ' on host=' + target.tempHost);
-              if (!!target.hosts) {
-                return getHostAppIdData(target);
-              } else {
-                return getServiceAppIdData(target);
-              }
-            });
           }
-
-          return $q.all(metricsPromises).then(function(metricsDataArray) {
-            var data = _.map(metricsDataArray, function(metricsData) {
-              return metricsData.data;
-            });
-            var metricsDataResult = {data: _.flatten(data)};
-            return $q.when(metricsDataResult);
+          if (indexOfHosts >= 0) {
+            var allHosts = templateSrv._values.hosts.lastIndexOf('}') > 0 ? templateSrv._values.hosts.slice(1, -1) :
+              templateSrv._values.hosts;
+            allHosts = templateSrv._texts.hosts === "All" ? '%' : allHosts;
+            metricsPromises.push(_.map(options.targets, function (target) {
+              target.templatedHost = allHosts ? allHosts : '';
+              target.templatedCluster = templatedCluster;
+              return getAllHostData(target);
+            }));
+          }
+          metricsPromises = _.flatten(metricsPromises);
+        } else {
+          // Non Templatized Dashboards
+          metricsPromises = _.map(options.targets, function (target) {
+            console.debug('target app=' + target.app + ',' +
+              'target metric=' + target.metric + ' on host=' + target.tempHost);
+            if (!!target.hosts) {
+              return getHostAppIdData(target);
+            } else {
+              return getServiceAppIdData(target);
+            }
           });
-        };
+        }
 
-        /**
-         * AMS Datasource  List Series.
-         */
-        AmbariMetricsDatasource.prototype.listSeries = function (query) {
-          // wrap in regex
-          if (query && query.length > 0 && query[0] !== '/') {
-            query = '/' + query + '/';
+        return $q.all(metricsPromises).then(function (metricsDataArray) {
+          var data = _.map(metricsDataArray, function (metricsData) {
+            return metricsData.data;
+          });
+          var metricsDataResult = {data: _.flatten(data)};
+          return $q.when(metricsDataResult);
+        });
+      };
+
+      /**
+       * AMS Datasource  List Series.
+       */
+      this.listSeries = function (query) {
+        // wrap in regex
+        if (query && query.length > 0 && query[0] !== '/') {
+          query = '/' + query + '/';
+        }
+        return $q.when([]);
+      };
+
+      /**
+       * AMS Datasource Templating Variables.
+       */
+      this.metricFindQuery = function (query) {
+        var interpolated;
+        try {
+          interpolated = query.split('.')[0];
+        } catch (err) {
+          return $q.reject(err);
+        }
+        var templatedClusters = templateSrv.variables.filter(function (o) {
+          return o.name === "cluster"
+        });
+        var templatedCluster = (_.isEmpty(templatedClusters)) ? '' : templatedClusters[0].options.filter(function (cluster) {
+          return cluster.selected;
+        }).map(function (clusterName) {
+          return clusterName.value;
+        });
+
+        var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function (variable) {
+          return variable.name === "components"
+        });
+        var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
+
+
+        // Templated Variable for HBase Users
+        // It will search the cluster and populate the HBase Users.
+        if (interpolated === "hbase-users") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var hbaseUsers = allMetrics["hbase"];
+              var extractUsers = hbaseUsers.filter(/./.test.bind(new RegExp("regionserver.Users.", 'g')));
+              var removeUser = "regionserver.Users.numUsers";
+              var i = extractUsers.indexOf(removeUser);
+              if (i !== -1) {
+                extractUsers.splice(i, 1);
+              }
+              var userPrefix = "regionserver.Users.";
+              var users = _.map(extractUsers, function (user) {
+                return user.substring(userPrefix.length);
+              });
+              users = _.map(users, function (userName) {
+                return userName.substring(0, userName.lastIndexOf("_metric"));
+              });
+              users = _.sortBy(_.uniq(users));
+              return _.map(users, function (users) {
+                return {
+                  text: users
+                };
+              });
+            });
+        }
+        // Templated Variable for HBase Tables.
+        // It will search the cluster and populate the hbase-tables.
+        if (interpolated === "hbase-tables") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var hbaseTables = allMetrics["hbase"];
+              var extractTables = hbaseTables.filter(/./.test.bind(new RegExp("regionserver.Tables.", 'g')));
+              var removeTable = "regionserver.Tables.numTables";
+              var i = extractTables.indexOf(removeTable);
+              if (i != -1) {
+                extractTables.splice(i, 1);
+              }
+              var tablePrefix = "regionserver.Tables.";
+              var tables = _.map(extractTables, function (user) {
+                return user.substring(tablePrefix.length);
+              });
+              tables = _.map(tables, function (userName) {
+                return userName.substring(0, userName.lastIndexOf("_metric"));
+              });
+              tables = _.sortBy(_.uniq(tables));
+              return _.map(tables, function (tables) {
+                return {
+                  text: tables
+                };
+              });
+            });
+        }
+        // Templated Variable for Kafka Topics.
+        // It will search the cluster and populate the topics.
+        if (interpolated === "kafka-topics") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var kafkaTopics = allMetrics["kafka_broker"];
+              var extractTopics = kafkaTopics.filter(/./.test.bind(new RegExp("\\b.log.Log.\\b", 'g')));
+              var topics = _.map(extractTopics, function (topic) {
+                var topicPrefix = "topic.";
+                return topic.substring(topic.lastIndexOf(topicPrefix) + topicPrefix.length, topic.length);
+              });
+              topics = _.sortBy(_.uniq(topics));
+              var i = topics.indexOf("ambari_kafka_service_check");
+              if (i != -1) {
+                topics.splice(i, 1);
+              }
+              return _.map(topics, function (topics) {
+                return {
+                  text: topics
+                };
+              });
+            });
+        }
+
+        //Templated Variables for Call Queue Metrics
+        if (interpolated === "callers") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var nnCallers = allMetrics["namenode"];
+              var extractCallers = nnCallers.filter(/./.test.bind(new
+              RegExp("ipc.client.org.apache.hadoop.ipc.DecayRpcScheduler.Caller", 'g')));
+              var callers = _.sortBy(_.uniq(_.map(extractCallers, function (caller) {
+                return caller.substring(caller.indexOf('(') + 1, caller.indexOf(')'))
+              })));
+              return _.map(callers, function (callers) {
+                return {
+                  text: callers
+                };
+              });
+            });
+        }
+
+        var cores = [];
+        //Templated Variables for Infra Solr Cores
+        if (interpolated === "infra_solr_core") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var solrMetrics = allMetrics["ambari-infra-solr"];
+              var extractCores = solrMetrics.filter(/./.test.bind(new
+              RegExp("^infra.solr.core.", 'g')));
+              _.map(extractCores, function (core) {
+                // Core naming convention is infra.solr.core.<collection_name>.<shard>.<replica>.<metric_name>
+                // coreName should be <collection_name>.<shard>.<replica>
+                core = core.split('.');
+                var coreName = core.slice(3, 6).join(".");
+                if (cores.indexOf(coreName) < 0) {
+                  cores.push(coreName);
+                }
+              });
+              return _.map(cores, function (cores) {
+                return {
+                  text: cores
+                };
+              });
+            });
+        }
+
+        var collections = [];
+        //Templated Variables for Infra Solr Collections
+        if (interpolated === "infra_solr_collection") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var solrMetrics = allMetrics["ambari-infra-solr"];
+              var extractCollections = solrMetrics.filter(/./.test.bind(new
+              RegExp("^infra.solr.core.", 'g')));
+              _.map(extractCollections, function (core) {
+                // Core naming convention is infra.solr.core.<collection_name>.<shard>.<replica>.<metric_name>
+                core = core.split('.');
+                var collection = core[3];
+                if (collections.indexOf(collection) < 0) {
+                  collections.push(collection);
+                }
+              });
+              return _.map(collections, function (collections) {
+                return {
+                  text: collections
+                };
+              });
+            });
+        }
+
+        var topologies = {};
+        //Templated Variables for Storm Topologies
+        if (interpolated === "topologies") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var storm = allMetrics["nimbus"];
+              var extractTopologies = storm.filter(/./.test.bind(new
+              RegExp("^topology.", 'g')));
+              _.map(extractTopologies, function (topology) {
+                // Topology naming convention is topology.<topology-name>.component.
+                topology = topology.split('.').slice(0, 3);
+                if (topologies[topology[1]]) {
+                  topologies[topology[1]].push(topology[2]);
+                } else {
+                  topologies[topology[1]] = [topology[2]];
+                }
+              });
+              return _.map(Object.keys(topologies), function (topologyNames) {
+                return {
+                  text: topologyNames
+                };
+              });
+            });
+        }
+        //Templated Variables for Storm Components per Topology
+        if (interpolated.indexOf("stormComponent") >= 0) {
+          var componentName = interpolated.substring(0, interpolated.indexOf('.'));
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var storm = allMetrics["nimbus"];
+              var extractTopologies = storm.filter(/./.test.bind(new
+              RegExp("^topology.", 'g')));
+              _.map(extractTopologies, function (topology) {
+                topology = topology.split('.').slice(0, 3);
+                if (topologies[topology[1]]) {
+                  topologies[topology[1]].push(topology[2]);
+                } else {
+                  topologies[topology[1]] = [topology[2]];
+                }
+              });
+              // Retrieve unique component names from the list.
+              var compName = _.uniq(topologies[componentName]);
+              // Remove "kafka-topic" from the list of components.
+              var remove = compName.indexOf('kafka-topic');
+              if (remove > -1) {
+                compName.splice(remove, 1);
+              }
+              return _.map(compName, function (components) {
+                return {
+                  text: components
+                };
+              });
+            });
+        }
+        var stormEntities = {};
+        this.getStormEntities = function () {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var storm = allMetrics["nimbus"];
+              var extractTopologies = storm.filter(/./.test.bind(new
+              RegExp("partition", 'g')));
+              _.map(extractTopologies, function (topology) {
+                topology = topology.split('.').slice(0, 5);
+                var topologyName = topologyN = topology[1]; // Topology
+                var topologyTopicName = topicN = topology[3]; // Topic
+                var topologyTopicPartitionName = topology[4]; // Partition
+                if (stormEntities[topologyName]) {
+                  if (stormEntities[topologyName][topologyTopicName]) {
+                    stormEntities[topologyName][topologyTopicName].push(topologyTopicPartitionName);
+                  } else {
+                    stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
+                  }
+                } else {
+                  stormEntities[topologyName] = {};
+                  stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
+                }
+              });
+            });
+        };
+        //Templated Variables for Storm Topics per Topology
+        if (interpolated.indexOf("stormTopic") >= 0) {
+          var topicName = interpolated.substring(0, interpolated.indexOf('.'));
+          return this.getStormEntities().then(function () {
+            var topicNames = Object.keys(stormEntities[topicName]);
+            return _.map(topicNames, function (names) {
+              return {
+                text: names
+              };
+            });
+          });
+        }
+        //Templated Variables for Storm Partitions per Topic
+        if (interpolated.indexOf("stormPartition") >= 0) {
+          var topicN, topologyN;
+          return this.getStormEntities().then(function () {
+            var partitionNames = _.uniq(stormEntities[topologyN][topicN]);
+            return _.map(partitionNames, function (names) {
+              return {
+                text: names
+              };
+            });
+          });
+        }
+        // Templated Variable for YARN Queues.
+        // It will search the cluster and populate the queues.
+        if (interpolated === "yarnqueues") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var yarnqueues = allMetrics["resourcemanager"];
+              var extractQueues = yarnqueues.filter(/./.test.bind(new RegExp(".=root", 'g')));
+              var queues = _.map(extractQueues, function (metric) {
+                return metric.substring("yarn.QueueMetrics.Queue=".length);
+              });
+              queues = _.map(queues, function (metricName) {
+                return metricName.substring(metricName.lastIndexOf("."), 0);
+              });
+              queues = _.sortBy(_.uniq(queues));
+              return _.map(queues, function (queues) {
+                return {
+                  text: queues
+                };
+              });
+            });
+        }
+
+        // Templated Variable for DruidServices.
+        // It will search the cluster and populate the druid service names.
+        if (interpolated === "druidServices") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var druidMetrics = allMetrics["druid"];
+              // Assumption: each node always emits jvm metrics
+              var extractNodeTypes = druidMetrics.filter(/./.test.bind(new RegExp("jvm/gc/time", 'g')));
+              var nodeTypes = _.map(extractNodeTypes, function (metricName) {
+                return metricName.substring(0, metricName.indexOf("."));
+              });
+              nodeTypes = _.sortBy(_.uniq(nodeTypes));
+              return _.map(nodeTypes, function (nodeType) {
+                return {
+                  text: nodeType
+                };
+              });
+            });
+        }
+
+        // Templated Variable for Druid datasources.
+        // It will search the cluster and populate the druid datasources.
+        if (interpolated === "druidDataSources") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var druidMetrics = allMetrics["druid"];
+              // Assumption: query/time is emitted for each datasource
+              var extractDataSources = druidMetrics.filter(/./.test.bind(new RegExp("query/time", 'g')));
+              var dataSources = _.map(extractDataSources, function (metricName) {
+                return metricName.split('.')[1]
+              });
+              dataSources = _.sortBy(_.uniq(dataSources));
+              return _.map(dataSources, function (dataSource) {
+                return {
+                  text: dataSource
+                };
+              });
+            });
+        }
+
+        // Templated Variable for Druid query type.
+        // It will search the cluster and populate the druid query types.
+        if (interpolated === "druidQueryTypes") {
+          return this.initMetricAppidMapping()
+            .then(function () {
+              var druidMetrics = allMetrics["druid"];
+              // Assumption: query/time is emitted for each query type.
+              var extractQueryTypes = druidMetrics.filter(/./.test.bind(new RegExp("query/time", 'g')));
+              var queryTypes = _.map(extractQueryTypes, function (metricName) {
+                return metricName.split('.')[2]
+              });
+              queryTypes = _.sortBy(_.uniq(queryTypes));
+              return _.map(queryTypes, function (queryType) {
+                return {
+                  text: queryType
+                };
+              });
+            });
+        }
+
+        if (interpolated == 'hosts') {
+          return this.suggestHosts(tComponent, templatedCluster);
+        } else if (interpolated == 'cluster') {
+          return this.suggestClusters(tComponent)
+        }
+      };
+
+      /**
+       * AMS Datasource  - Test Data Source Connection.
+       *
+       * Added Check to see if Datasource is working. Throws up an error in the
+       * Datasources page if incorrect info is passed on.
+       */
+      this.testDatasource = function () {
+        return this.doAmbariRequest({
+          url: '/ws/v1/timeline/metrics/metadata',
+          method: 'GET'
+        }).then(function (response) {
+          console.log(response);
+          if (response.status === 200) {
+            return {status: "success", message: "Data source is working", title: "Success"};
           }
+        });
+      };
+
+      /**
+       * AMS Datasource - Suggest AppId.
+       *
+       * Read AppIds from cache.
+       */
+      this.suggestApps = function (query) {
+        console.log(query);
+
+        appIds = appIds.sort();
+        var appId = _.map(appIds, function (k) {
+          return {text: k};
+        });
+        return $q.when(appId);
+      };
+
+      /**
+       * AMS Datasource - Suggest Metrics.
+       *
+       * Read Metrics based on AppId chosen.
+       */
+      this.suggestMetrics = function (query, app) {
+        if (!app) {
           return $q.when([]);
-        };
+        }
+        var keys = [];
+        keys = _.map(allMetrics[app], function (m) {
+          return {text: m};
+        });
+        keys = _.sortBy(keys, function (i) {
+          return i.text.toLowerCase();
+        });
+        return $q.when(keys);
+      };
 
-        /**
-         * AMS Datasource Templating Variables.
-         */
-        AmbariMetricsDatasource.prototype.metricFindQuery = function (query) {
-          var interpolated;
-          try {
-            interpolated = query.split('.')[0];
-          } catch (err) {
-            return $q.reject(err);
-          }
-          var templatedClusters = templateSrv.variables.filter(function(o) { return o.name === "cluster"});
-          var templatedCluster = (_.isEmpty(templatedClusters)) ? '' : templatedClusters[0].options.filter(function(cluster)
-          { return cluster.selected; }).map(function(clusterName) { return clusterName.value; });
-
-          var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function(variable) 
-            { return variable.name === "components"});
-          var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
-
-
-          // Templated Variable for HBase Users
-          // It will search the cluster and populate the HBase Users.
-          if(interpolated === "hbase-users") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var hbaseUsers = allMetrics["hbase"];
-                var extractUsers = hbaseUsers.filter(/./.test.bind(new RegExp("regionserver.Users.", 'g')));
-                var removeUser = "regionserver.Users.numUsers";
-                var i = extractUsers.indexOf(removeUser);
-                if(i !== -1) { extractUsers.splice(i, 1);}
-                var userPrefix = "regionserver.Users.";
-                var users = _.map(extractUsers, function(user) {
-                  return user.substring(userPrefix.length);
-                });
-                users = _.map(users, function(userName) {
-                  return userName.substring(0,userName.lastIndexOf("_metric"));
-                });
-                users = _.sortBy(_.uniq(users));
-                return _.map(users, function (users) {
-                  return {
-                    text: users
-                  };
-                });
-              });
-          }
-          // Templated Variable for HBase Tables.
-          // It will search the cluster and populate the hbase-tables.
-          if(interpolated === "hbase-tables") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var hbaseTables = allMetrics["hbase"];
-                var extractTables = hbaseTables.filter(/./.test.bind(new RegExp("regionserver.Tables.", 'g')));
-                var removeTable = "regionserver.Tables.numTables";
-                var i = extractTables.indexOf(removeTable);
-                if(i != -1) { extractTables.splice(i, 1);}
-                var tablePrefix = "regionserver.Tables.";
-                var tables = _.map(extractTables, function(user) {
-                  return user.substring(tablePrefix.length);
-                });
-                tables = _.map(tables, function(userName) {
-                  return userName.substring(0,userName.lastIndexOf("_metric"));
-                });
-                tables = _.sortBy(_.uniq(tables));
-                return _.map(tables, function (tables) {
-                  return {
-                    text: tables
-                  };
-                });
-              });
-          }
-          // Templated Variable for Kafka Topics.
-          // It will search the cluster and populate the topics.
-          if(interpolated === "kafka-topics") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var kafkaTopics = allMetrics["kafka_broker"];
-                var extractTopics = kafkaTopics.filter(/./.test.bind(new RegExp("\\b.log.Log.\\b", 'g')));
-                var topics =_.map(extractTopics, function (topic) {
-                  var topicPrefix = "topic.";
-                  return topic.substring(topic.lastIndexOf(topicPrefix)+topicPrefix.length, topic.length);
-                });
-                topics = _.sortBy(_.uniq(topics));
-                var i = topics.indexOf("ambari_kafka_service_check");
-                if(i != -1) { topics.splice(i, 1);}
-                return _.map(topics, function (topics) {
-                  return {
-                    text: topics
-                  };
-                });
-              });
-          }
-
-          //Templated Variables for Call Queue Metrics
-          if(interpolated === "callers") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var nnCallers = allMetrics["namenode"];
-                var extractCallers = nnCallers.filter(/./.test.bind(new 
-                  RegExp("ipc.client.org.apache.hadoop.ipc.DecayRpcScheduler.Caller", 'g')));
-                var callers = _.sortBy(_.uniq(_.map(extractCallers, function(caller) { 
-                  return caller.substring(caller.indexOf('(')+1, caller.indexOf(')')) })));
-                return _.map(callers, function (callers) {
-                  return {
-                    text: callers
-                  };
-                });
-              });
-          }
-
-          var cores = [];
-          //Templated Variables for Infra Solr Cores
-          if (interpolated === "infra_solr_core") {
-              return this.initMetricAppidMapping()
-                  .then(function () {
-                      var solrMetrics = allMetrics["ambari-infra-solr"];
-                      var extractCores = solrMetrics.filter(/./.test.bind(new
-                      RegExp("^infra.solr.core.", 'g')));
-                      _.map(extractCores, function (core) {
-                          // Core naming convention is infra.solr.core.<collection_name>.<shard>.<replica>.<metric_name>
-                          // coreName should be <collection_name>.<shard>.<replica>
-                          core = core.split('.');
-                          var coreName = core.slice(3,6).join(".");
-                          if (cores.indexOf(coreName) < 0) {
-                              cores.push(coreName);
-                          }
-                      });
-                      return _.map(cores, function (cores) {
-                              return {
-                                  text: cores
-                              };
-                          });
-                      });
-          }
-
-          var collections = [];
-          //Templated Variables for Infra Solr Collections
-          if (interpolated === "infra_solr_collection") {
-              return this.initMetricAppidMapping()
-                  .then(function () {
-                      var solrMetrics = allMetrics["ambari-infra-solr"];
-                      var extractCollections = solrMetrics.filter(/./.test.bind(new
-                      RegExp("^infra.solr.core.", 'g')));
-                      _.map(extractCollections, function (core) {
-                          // Core naming convention is infra.solr.core.<collection_name>.<shard>.<replica>.<metric_name>
-                          core = core.split('.');
-                          var collection = core[3];
-                          if (collections.indexOf(collection) < 0) {
-                              collections.push(collection);
-                          }
-                      });
-                      return _.map(collections, function (collections) {
-                              return {
-                                  text: collections
-                              };
-                          });
-                      });
-          }
-
-          var topologies = {};
-          //Templated Variables for Storm Topologies
-          if(interpolated === "topologies") {
-            return this.initMetricAppidMapping()
-                .then(function () {
-                  var storm = allMetrics["nimbus"];
-                  var extractTopologies = storm.filter(/./.test.bind(new
-                      RegExp("^topology.", 'g')));
-                  _.map(extractTopologies, function(topology){
-                    // Topology naming convention is topology.<topology-name>.component.
-                    topology = topology.split('.').slice(0,3);
-                    if (topologies[topology[1]]){
-                      topologies[topology[1]].push(topology[2]);
-                    } else {
-                      topologies[topology[1]] = [topology[2]];
-                    }
-                  });
-                  return _.map(Object.keys(topologies), function(topologyNames){
-                    return {
-                      text: topologyNames
-                    };
-                  });
-                });
-          }
-          //Templated Variables for Storm Components per Topology
-          if (interpolated.indexOf("stormComponent") >= 0) {
-            var componentName = interpolated.substring(0,interpolated.indexOf('.'));
-            return this.initMetricAppidMapping()
-                .then(function () {
-                  var storm = allMetrics["nimbus"];
-                  var extractTopologies = storm.filter(/./.test.bind(new
-                      RegExp("^topology.", 'g')));
-                  _.map(extractTopologies, function(topology){
-                    topology = topology.split('.').slice(0,3);
-                    if (topologies[topology[1]]){
-                      topologies[topology[1]].push(topology[2]);
-                    } else {
-                      topologies[topology[1]] = [topology[2]];
-                    }
-                  });
-                  // Retrieve unique component names from the list.
-                  var compName = _.uniq(topologies[componentName]);
-                  // Remove "kafka-topic" from the list of components.
-                  var remove = compName.indexOf('kafka-topic');
-                  if (remove > -1) { compName.splice(remove, 1);}
-                  return _.map(compName, function(components){
-                    return {
-                      text: components
-                    };
-                  });
-                });
-          }
-          var stormEntities = {};
-          AmbariMetricsDatasource.prototype.getStormEntities = function () {
-            return this.initMetricAppidMapping()
-                .then(function () {
-                  var storm = allMetrics["nimbus"];
-                  var extractTopologies = storm.filter(/./.test.bind(new
-                      RegExp("partition", 'g')));
-                  _.map(extractTopologies, function(topology){
-                    topology = topology.split('.').slice(0,5);
-                    var topologyName = topologyN = topology[1]; // Topology
-                    var topologyTopicName = topicN = topology[3]; // Topic
-                    var topologyTopicPartitionName = topology[4]; // Partition
-                    if (stormEntities[topologyName]) {
-                      if (stormEntities[topologyName][topologyTopicName]) {
-                        stormEntities[topologyName][topologyTopicName].push(topologyTopicPartitionName);
-                      } else {
-                        stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
-                      }
-                    } else {
-                      stormEntities[topologyName] = {};
-                      stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
-                    }
-                  });
-                });
-          };
-          //Templated Variables for Storm Topics per Topology
-          if (interpolated.indexOf("stormTopic") >= 0) {
-            var topicName = interpolated.substring(0,interpolated.indexOf('.'));
-            return this.getStormEntities().then(function () {
-              var topicNames = Object.keys(stormEntities[topicName]);
-              return _.map(topicNames, function(names){
-                return {
-                  text: names
-                };
-              });
-            });
-          }
-          //Templated Variables for Storm Partitions per Topic
-          if (interpolated.indexOf("stormPartition") >= 0) {
-            var topicN, topologyN;
-            return this.getStormEntities().then(function () {
-              var partitionNames = _.uniq(stormEntities[topologyN][topicN]);
-              return _.map(partitionNames, function(names){
-                return {
-                  text: names
-                };
-              });
-            });
-          }
-          // Templated Variable for YARN Queues.
-          // It will search the cluster and populate the queues.
-          if(interpolated === "yarnqueues") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var yarnqueues = allMetrics["resourcemanager"];
-                var extractQueues = yarnqueues.filter(/./.test.bind(new RegExp(".=root", 'g')));
-                var queues = _.map(extractQueues, function(metric) {
-                  return metric.substring("yarn.QueueMetrics.Queue=".length);
-                });
-                queues = _.map(queues, function(metricName) {
-                  return metricName.substring(metricName.lastIndexOf("."), 0);
-                });
-                queues = _.sortBy(_.uniq(queues));
-                return _.map(queues, function (queues) {
-                  return {
-                    text: queues
-                  };
-                });
-              });
-          }
-
-          // Templated Variable for DruidServices.
-          // It will search the cluster and populate the druid service names.
-          if(interpolated === "druidServices") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var druidMetrics = allMetrics["druid"];
-                // Assumption: each node always emits jvm metrics
-                var extractNodeTypes = druidMetrics.filter(/./.test.bind(new RegExp("jvm/gc/time", 'g')));
-                var nodeTypes = _.map(extractNodeTypes, function(metricName) {
-                  return metricName.substring(0, metricName.indexOf("."));
-                });
-                nodeTypes = _.sortBy(_.uniq(nodeTypes));
-                return _.map(nodeTypes, function (nodeType) {
-                  return {
-                    text: nodeType
-                  };
-                });
-              });
-          }
-
-          // Templated Variable for Druid datasources.
-          // It will search the cluster and populate the druid datasources.
-          if(interpolated === "druidDataSources") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var druidMetrics = allMetrics["druid"];
-                // Assumption: query/time is emitted for each datasource
-                var extractDataSources = druidMetrics.filter(/./.test.bind(new RegExp("query/time", 'g')));
-                var dataSources = _.map(extractDataSources, function(metricName) {
-                  return metricName.split('.')[1]
-                });
-                dataSources = _.sortBy(_.uniq(dataSources));
-                return _.map(dataSources, function (dataSource) {
-                  return {
-                    text: dataSource
-                  };
-                });
-              });
-          }
-
-          // Templated Variable for Druid query type.
-          // It will search the cluster and populate the druid query types.
-          if(interpolated === "druidQueryTypes") {
-            return this.initMetricAppidMapping()
-              .then(function () {
-                var druidMetrics = allMetrics["druid"];
-                // Assumption: query/time is emitted for each query type.
-                var extractQueryTypes = druidMetrics.filter(/./.test.bind(new RegExp("query/time", 'g')));
-                var queryTypes = _.map(extractQueryTypes, function(metricName) {
-                  return metricName.split('.')[2]
-                });
-                queryTypes = _.sortBy(_.uniq(queryTypes));
-                return _.map(queryTypes, function (queryType) {
-                  return {
-                    text: queryType
-                  };
-                });
-              });
-          }
-
-          if (interpolated == 'hosts') {
-            return this.suggestHosts(tComponent, templatedCluster);
-          } else if (interpolated == 'cluster') {
-            return this.suggestClusters(tComponent)
-          }
-        };
-
-        /**
-         * AMS Datasource  - Test Data Source Connection.
-         *
-         * Added Check to see if Datasource is working. Throws up an error in the
-         * Datasources page if incorrect info is passed on.
-         */
-        AmbariMetricsDatasource.prototype.testDatasource = function () {
-          return this.doAmbariRequest({
-            url: '/ws/v1/timeline/metrics/metadata',
-            method: 'GET'
-          }).then(function(response) {
-            console.log(response);
-            if (response.status === 200) {
-              return { status: "success", message: "Data source is working", title: "Success" };
+      this.suggestClusters = function (app) {
+        if (!app) {
+          app = '';
+        }
+        return this.doAmbariRequest({
+          method: 'GET',
+          url: '/ws/v1/timeline/metrics/instances?' + 'appId=' + app
+        }).then(function (response) {
+          var clusters = [];
+          var data = response.data;
+          for (var cluster in data) {
+            if (data[cluster].hasOwnProperty(app)) {
+              clusters.push({text: cluster});
             }
-          });
-        };
-
-        /**
-         * AMS Datasource - Suggest AppId.
-         *
-         * Read AppIds from cache.
-         */
-        AmbariMetricsDatasource.prototype.suggestApps = function (query) {
-          console.log(query);
-
-          appIds = appIds.sort();
-          var appId = _.map(appIds, function (k) {
-            return {text: k};
-          });
-          return $q.when(appId);
-        };
-
-        /**
-         * AMS Datasource - Suggest Metrics.
-         *
-         * Read Metrics based on AppId chosen.
-         */
-        AmbariMetricsDatasource.prototype.suggestMetrics = function (query, app) {
-          if (!app) {
-            return $q.when([]);
           }
-          var keys = [];
-          keys = _.map(allMetrics[app],function(m) {
-            return {text: m};
-          });
-          keys = _.sortBy(keys, function (i) { return i.text.toLowerCase(); });
-          return $q.when(keys);
-        };
+          return $q.when(clusters);
+        });
+      };
 
-        AmbariMetricsDatasource.prototype.suggestClusters = function(app) {
-          if (!app) { app = ''; }
-          return this.doAmbariRequest({
-            method: 'GET',
-            url: '/ws/v1/timeline/metrics/instances?' + 'appId=' + app
-          }).then(function(response) {
-              var clusters = [];
-              var data = response.data;
-              for (var cluster in data) {
-                if (data[cluster].hasOwnProperty(app)) {
-                  clusters.push({text: cluster});
-                }
-              }
-              return $q.when(clusters);
-          });
-        };
-
-        /**
-         * AMS Datasource - Suggest Hosts.
-         *
-         * Query Hosts on the cluster.
-         */
-        AmbariMetricsDatasource.prototype.suggestHosts = function (app, cluster) {
-          if (!app) { app = ''; }
-          if (!cluster) { cluster = ''; }
-          return this.doAmbariRequest({
-            method: 'GET',
-            url: '/ws/v1/timeline/metrics/instances?' + 'appId=' + app + '&instanceId=' + cluster
-          }).then(function (response) {
-            var hosts = [];
-            var data = response.data;
-            for (var cluster in data) {
-              var appHosts = data[cluster][app];
-              if (appHosts) {
-                for (var index in appHosts) {
-                  hosts.push({text: appHosts[index]});
-                }
+      /**
+       * AMS Datasource - Suggest Hosts.
+       *
+       * Query Hosts on the cluster.
+       */
+      this.suggestHosts = function (app, cluster) {
+        if (!app) {
+          app = '';
+        }
+        if (!cluster) {
+          cluster = '';
+        }
+        return this.doAmbariRequest({
+          method: 'GET',
+          url: '/ws/v1/timeline/metrics/instances?' + 'appId=' + app + '&instanceId=' + cluster
+        }).then(function (response) {
+          var hosts = [];
+          var data = response.data;
+          for (var cluster in data) {
+            var appHosts = data[cluster][app];
+            if (appHosts) {
+              for (var index in appHosts) {
+                hosts.push({text: appHosts[index]});
               }
             }
-            return $q.when(hosts);
-          });
-        };
-
-        /**
-         * AMS Datasource Aggregators.
-         */
-        var aggregatorsPromise = null;
-        AmbariMetricsDatasource.prototype.getAggregators = function () {
-          if (aggregatorsPromise) {
-            return aggregatorsPromise;
           }
-          aggregatorsPromise = $q.when([
-            'none','avg', 'sum', 'min', 'max'
-          ]);
+          return $q.when(hosts);
+        });
+      };
+
+      /**
+       * AMS Datasource Aggregators.
+       */
+      var aggregatorsPromise = null;
+      this.getAggregators = function () {
+        if (aggregatorsPromise) {
           return aggregatorsPromise;
-        };
+        }
+        aggregatorsPromise = $q.when([
+          'none', 'avg', 'sum', 'min', 'max'
+        ]);
+        return aggregatorsPromise;
+      };
+    };
 
-        return AmbariMetricsDatasource;
-      });
-    }
-);
+    return {
+      AmbariMetricsDatasource: AmbariMetricsDatasource
+    };
+
+
+  });
+
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
index aade7d7..087533c 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
@@ -34,3 +34,4 @@
   });
 
 });
+
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/ams-screenshot.png b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/ams-screenshot.png
new file mode 100644
index 0000000..358e42e
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/ams-screenshot.png
Binary files differ
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo-sm.png b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo-sm.png
new file mode 100644
index 0000000..0f90391
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo-sm.png
Binary files differ
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo.png b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo.png
new file mode 100644
index 0000000..07412bd
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo.png
Binary files differ
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-project.png b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-project.png
new file mode 100644
index 0000000..7ce8965
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-project.png
Binary files differ
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.d.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.d.ts
new file mode 100644
index 0000000..3e12e14
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.d.ts
@@ -0,0 +1,21 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { AmbariMetricsDatasource } from './datasource';
+import { AmbariMetricsQueryCtrl } from './query_ctrl';
+import { AmbariMetricsConfigCtrl } from './config_ctrl';
+export { AmbariMetricsDatasource as Datasource, AmbariMetricsQueryCtrl as QueryCtrl, AmbariMetricsConfigCtrl as ConfigCtrl };
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js
new file mode 100644
index 0000000..ebc4f8a
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js
@@ -0,0 +1,21 @@
+System.register(['./datasource', './query_ctrl', './config_ctrl'], function(exports_1) {
+    var datasource_1, query_ctrl_1, config_ctrl_1;
+    return {
+        setters:[
+            function (datasource_1_1) {
+                datasource_1 = datasource_1_1;
+            },
+            function (query_ctrl_1_1) {
+                query_ctrl_1 = query_ctrl_1_1;
+            },
+            function (config_ctrl_1_1) {
+                config_ctrl_1 = config_ctrl_1_1;
+            }],
+        execute: function() {
+            exports_1("Datasource", datasource_1.AmbariMetricsDatasource);
+            exports_1("QueryCtrl", query_ctrl_1.AmbariMetricsQueryCtrl);
+            exports_1("ConfigCtrl", config_ctrl_1.AmbariMetricsConfigCtrl);
+        }
+    }
+});
+//# sourceMappingURL=module.js.map
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js.map b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js.map
new file mode 100644
index 0000000..5bdb60e
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../../../public/app/plugins/datasource/ambari-metrics/module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;YAsB+B,6DAAU;YACX,2DAAS;YACR,8DAAU"}
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.ts
new file mode 100644
index 0000000..137e7c7
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.ts
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {AmbariMetricsDatasource} from './datasource';
+import {AmbariMetricsQueryCtrl} from './query_ctrl';
+import {AmbariMetricsConfigCtrl} from './config_ctrl';
+
+export {
+    AmbariMetricsDatasource as Datasource,
+    AmbariMetricsQueryCtrl as QueryCtrl,
+    AmbariMetricsConfigCtrl as ConfigCtrl
+};
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/annotations.editor.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/annotations.editor.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/annotations.editor.html
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
index 360c15c..d4ad4b3 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
@@ -15,5 +15,4 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<div ng-include="httpConfigPartialSrc"></div>
-<br>
+<datasource-http-settings current="ctrl.current"></datasource-http-settings>
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
index 7e78cc0..e0f1461 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.editor.html
@@ -15,162 +15,98 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<div class="tight-form">
-    <ul class="tight-form-list pull-right">
-        <li class="tight-form-item small" ng-show="target.datasource">
-            <em>{{target.datasource}}</em>
-        </li>
-        <li class="tight-form-item">
-            <div class="dropdown">
-                <a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
-                    <i class="fa fa-bars"></i>
-                </a>
-                <ul class="dropdown-menu pull-right" role="menu">
-                    <li role="menuitem"><a tabindex="1" ng-click="toggleQueryMode()">Switch editor mode</a></li>
-                    <li role="menuitem"><a tabindex="1" ng-click="duplicateDataQuery(target)">Duplicate</a></li>
-                    <li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index-1)">Move up</a></li>
-                    <li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index+1)">Move down</a></li>
-                </ul>
-            </div>
-        </li>
-        <li class="tight-form-item last">
-            <a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
-                <i class="fa fa-remove"></i>
-            </a>
-        </li>
-    </ul>
+<query-editor-row query-ctrl="ctrl" can-collapse="true">
+	<div class="gf-form-inline">
+		<div class="gf-form max-width-25">
+    		<label class="gf-form-label query-keyword width-8">
+        		Component
+    		</label>
+        	<input type="text" class="gf-form-input" ng-model="ctrl.target.app"
+               spellcheck='false' bs-typeahead="ctrl.suggestApps" placeholder="Component Name" data-min-length=0 data-items=100
+               ng-blur="ctrl.targetBlur()">
+        	</input>
+    </div>
 
-    <ul class="tight-form-list">
-        <li class="tight-form-item" style="min-width: 15px; text-align: center">
-            {{target.refId}}
-        </li>
-        <li>
-            <a  class="tight-form-item"
-                ng-click="target.hide = !target.hide; get_data();"
-                role="menuitem">
-                <i class="fa fa-eye"></i>
-            </a>
-        </li>
-    </ul>
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
+        	Metric
+    	</label>
+        <input type="text" class="input-large gf-form-input" ng-model="ctrl.target.metric"
+               spellcheck='false' bs-typeahead="ctrl.suggestMetrics" placeholder="metric name" data-min-length=0 data-items=100
+               ng-blur="ctrl.targetBlur()">
+        </input>
+        <a bs-tooltip="ctrl.target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="ctrl.target.errors.metric">
+            <i class="fa fa-warning"></i>
+        </a>
+    </div>
 
-    <ul class="tight-form-list" role="menu">
 
-        <li class="tight-form-item" style="width: 86px">
-        Component
-    </li>
-        <li>
-            <input type="text" class="input-large tight-form-input" ng-model="target.app"
-                   spellcheck='false' bs-typeahead="suggestApps" placeholder="Component Name" data-min-length=0 data-items=100
-                   ng-blur="targetBlur()">
-            </input>
-            <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
-                <i class="fa fa-warning"></i>
-            </a>
-        </li>
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
+        Hosts
+    	</label>
+    
+        <input type="text" class="input-large gf-form-input" ng-model="ctrl.target.hosts"
+               spellcheck='false' bs-typeahead="ctrl.suggestHosts" placeholder="host name" data-min-length=0 data-items=100
+               ng-blur="ctrl.targetBlur()">
+        </input>
+        <a bs-tooltip="ctrl.target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="ctrl.target.errors.metric">
+            <i class="fa fa-warning"></i>
+        </a>
+    </div>
 
-        <li class="tight-form-item" style="width: 86px">
-            Metric
-        </li>
-        <li>
-            <input type="text" class="input-large tight-form-input" ng-model="target.metric"
-                   spellcheck='false' bs-typeahead="suggestMetrics" placeholder="metric name" data-min-length=0 data-items=100
-                   ng-blur="targetBlur()">
-            </input>
-            <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
-                <i class="fa fa-warning"></i>
-            </a>
-        </li>
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
+        Aggregator
+    	</label>
+        <select ng-model="ctrl.target.aggregator" class="gf-form-input input-small"
+                ng-options="agg for agg in ctrl.aggregators"
+                ng-change="ctrl.targetBlur()">
+        </select>
+        <a bs-tooltip="ctrl.target.errors.aggregator" style="color: rgb(229, 189, 28)" ng-show="ctrl.target.errors.aggregator">
+            <i class="fa fa-warning"></i>
+        </a>
+    </div>
 
-        <li class="tight-form-item" style="width: 86px" ng-hide="dashboard.templating.list.length > 0">
-            Cluster
-        </li>
-        <li ng-hide="dashboard.templating.list.length > 0">
-            <input type="text" class="input-large tight-form-input" ng-model="target.cluster"
-                   spellcheck='false' bs-typeahead="suggestClusters" placeholder="cluster name" data-min-length=0 data-items=100
-                   ng-blur="targetBlur()">
-            </input>
-            <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
-                <i class="fa fa-warning"></i>
-            </a>
-        </li>
+	</div>
+	<div class="gf-form-inline">
 
-        <li class="tight-form-item" style="width: 86px" ng-hide="dashboard.templating.list.length > 0">
-            Hosts
-        </li>
-        <li ng-hide="dashboard.templating.list.length > 0">
-            <input type="text" class="input-large tight-form-input" ng-model="target.hosts"
-                   spellcheck='false' bs-typeahead="suggestHosts" placeholder="host name" data-min-length=0 data-items=100
-                   ng-blur="targetBlur()">
-            </input>
-            <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
-                <i class="fa fa-warning"></i>
-            </a>
-        </li>
-
-        <li class="tight-form-item">
-            Aggregator
-        </li>
-        <li>
-            <select ng-model="target.aggregator" class="tight-form-input input-small"
-                    ng-options="agg for agg in aggregators"
-                    ng-change="targetBlur()">
-            </select>
-            <a bs-tooltip="target.errors.aggregator" style="color: rgb(229, 189, 28)" ng-show="target.errors.aggregator">
-                <i class="fa fa-warning"></i>
-            </a>
-        </li>
-
-    </ul>
-
-    <div class="clearfix"></div>
-</div>
-
-<div class="tight-form">
-    <ul class="tight-form-list" role="menu">
-        <li class="tight-form-item tight-form-align" style="width: 86px">
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
             Alias
-        </li>
-        <li>
-            <input type="text" class="tight-form-input input-large"
-                   ng-model="target.alias"
+        </label>
+            <input type="text" class="gf-form-input input-large"
+                   ng-model="ctrl.target.alias"
                    spellcheck='false'
                    placeholder="series alias"
                    data-min-length=0 data-items=100
-                   ng-blur="targetBlur()"></input>
-            <a bs-tooltip="target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="target.errors.metric">
+                   ng-blur="ctrl.targetBlur()"></input>
+            <a bs-tooltip="ctrl.target.errors.metric" style="color: rgb(229, 189, 28)" ng-show="ctrl.target.errors.metric">
                 <i class="fa fa-warning"></i>
             </a>
-        </li>
-        <li class="tight-form-item tight-form-align">
-           Transform
-        </li>
-        <li>
-            <select ng-model="target.transform" class="tight-form-input input-small"
-                    ng-options="transform for transform in transforms"
-                    ng-init="transform()"
-                    ng-change="targetBlur()"></select>
-        </li>
+    </div>
+    
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
+            Transform
+        </label>
+            <select ng-model="ctrl.target.transform" class="gf-form-input input-small"
+                    ng-options="transform for transform in ctrl.transforms"
+                    ng-init="ctrl.transform()"
+                    ng-change="ctrl.targetBlur()"></select>
+    </div>
 
-        <li class="tight-form-item tight-form-align">
+
+    <div class="gf-form">
+    	<label class="gf-form-label query-keyword width-8">
             Precision
-        </li>
-        <li>
-            <select ng-model="target.precision" class="tight-form-input input-small"
-                    ng-options="precision for precision in precisions"
-                    ng-init="precisionInit()"
-                    ng-change="targetBlur()">
+        </label>
+            <select ng-model="ctrl.target.precision" class="gf-form-input input-small"
+                    ng-options="precision for precision in ctrl.precisions"
+                    ng-init="ctrl.precisionInit()"
+                    ng-change="ctrl.targetBlur()">
             </select>
-        </li>
-
-        <li class="tight-form-item">
-            Series Aggregator
-        </li>
-        <li>
-            <select ng-model="target.seriesAggregator" class="tight-form-input input-small"
-                    ng-options="seriesAggregator for seriesAggregator in seriesAggregators"
-                    ng-init="seriesAggregator()"
-                    ng-change="targetBlur()">
-            </select>
-        </li>
-    <div class="clearfix"></div>
+    </div>
+        <div class="clearfix"></div>
 </div>
+</query-editor-row>
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
deleted file mode 100644
index e58ca64..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one
-  ~ or more contributor license agreements.  See the NOTICE file
-  ~ distributed with this work for additional information
-  ~ regarding copyright ownership.  The ASF licenses this file
-  ~ to you under the Apache License, Version 2.0 (the
-  ~ "License"); you may not use this file except in compliance
-  ~ with the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<section class="grafana-metric-options">
-	<div class="tight-form last">
-		<ul class="tight-form-list">
-			<li class="tight-form-item tight-form-item-icon">
-				<i class="fa fa-info-circle"></i>
-			</li>
-			<li class="tight-form-item">
-				<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
-					Single Stats
-				</a>
-			</li>
-		</ul>
-		<div class="clearfix"></div>
-	</div>
-</section>
-
-<div class="editor-row">
-	<div class="pull-left" style="margin-top: 30px;">
-		<div class="grafana-info-box span6" ng-if="editorHelpIndex === 1">
-			<h5>Single Stats</h5>
-			<blockquote>To get the current value of the metric selected, Click on the <strong>Options</strong> tab above
-				and set the <strong>Big Value's</strong> value to <strong>"current"</strong>.</blockquote>
-		</div>
-	</div>
-</div>
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
index 5226ae7..643da57 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
@@ -1,14 +1,21 @@
 {
-  "pluginType": "datasource",
-  "name": "AmbariMetrics",
-
-  "type": "ambarimetrics",
-  "serviceName": "AmbariMetricsDatasource",
-
-  "module": "app/plugins/datasource/ambari-metrics/datasource",
-    "partials": {
-    "config": "app/plugins/datasource/ambari-metrics/partials/config.html"
+  "type": "datasource",
+  "name": "Ambari Metrics",
+  "id": "praj-ams-datasource",
+  "metrics": true,
+  "staticRoot": ".",
+  "defaultMatchFormat": "glob",
+  "info": {
+    "author": {
+      "name": "",
+      "url": ""
+    },
+    "links": [
+    ],
+    "logos": {
+      "small": "img/apache-ambari-logo-sm.png",
+      "large": "img/apache-ambari-logo.png"
+    },
+    "version": "1.0.1",
   },
-
-  "metrics": true
-}
\ No newline at end of file
+}
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
deleted file mode 100644
index 02b5813..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-define([
-      'angular',
-      'lodash'
-    ],
-    function (angular, _) {
-      'use strict';
-
-      var module = angular.module('grafana.controllers');
-
-      module.controller('AmbariMetricsQueryCtrl', function($scope) {
-
-        $scope.init = function() {
-          $scope.target.errors = validateTarget($scope.target);
-          $scope.aggregators = ['none','avg', 'sum', 'min', 'max'];
-          $scope.precisions = ['default','seconds', 'minutes', 'hours', 'days'];
-          $scope.transforms = ['none','diff','rate'];
-          $scope.seriesAggregators = ['none', 'avg', 'sum', 'min', 'max'];
-
-          if (!$scope.target.aggregator) {
-            $scope.target.aggregator = 'avg';
-          }
-          $scope.precisionInit = function () {
-           if (typeof $scope.target.precision == 'undefined') {
-                $scope.target.precision = "default";
-           }
-          };
-          $scope.transform = function () {
-           if (typeof $scope.target.transform == 'undefined') {
-                $scope.target.transform = "none";
-           }
-          };
-          $scope.seriesAggregator = function () {
-           if (typeof $scope.target.seriesAggregator == 'undefined') {
-                $scope.target.seriesAggregator = "none";
-           }
-          };
-          $scope.$watch('target.app', function (newValue) {
-            if (newValue === '') {
-              $scope.target.metric = '';
-              $scope.target.hosts = '';
-              $scope.target.cluster = '';
-            }
-          });
-          if (!$scope.target.downsampleAggregator) {
-            $scope.target.downsampleAggregator = 'avg';
-          }
-
-          $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.suggestApps = function(query, callback) {
-          $scope.datasource.suggestApps(query)
-            .then($scope.getTextValues)
-            .then(callback);
-        };
-
-        $scope.suggestClusters = function(query, callback) {
-          $scope.datasource.suggestClusters($scope.target.app)
-            .then($scope.getTextValues)
-            .then(callback);
-        };
-
-        $scope.suggestHosts = function(query, callback) {
-          $scope.datasource.suggestHosts($scope.target.app, $scope.target.cluster)
-            .then($scope.getTextValues)
-            .then(callback);
-        };
-
-        $scope.suggestMetrics = function(query, callback) {
-          $scope.datasource.suggestMetrics(query, $scope.target.app)
-            .then($scope.getTextValues)
-            .then(callback);
-        };
-
-        $scope.suggestTagKeys = function(query, callback) {
-          $scope.datasource.metricFindQuery('tag_names(' + $scope.target.metric + ')')
-              .then($scope.getTextValues)
-              .then(callback);
-        };
-
-        $scope.suggestTagValues = function(query, callback) {
-          $scope.datasource.metricFindQuery('tag_values(' + $scope.target.metric + ',' + $scope.target.currentTagKey + ')')
-              .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();
-        };
-
-        function validateTarget(target) {
-          var errs = {};
-
-          if (target.tags && _.has(target.tags, target.currentTagKey)) {
-            errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
-          }
-
-          return errs;
-        }
-
-        $scope.init();
-      });
-
-    });
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.d.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.d.ts
new file mode 100644
index 0000000..83363f7
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.d.ts
@@ -0,0 +1,21 @@
+/// <reference path="../../../../../public/app/headers/common.d.ts" />
+import { QueryCtrl } from 'app/plugins/sdk';
+export declare class AmbariMetricsQueryCtrl extends QueryCtrl {
+    static templateUrl: string;
+    aggregators: any;
+    aggregator: any;
+    errors: any;
+    precisions: any;
+    transforms: any;
+    transform: any;
+    precisionInit: any;
+    suggestMetrics: any;
+    suggestApps: any;
+    suggestHosts: any;
+    /** @ngInject **/
+    constructor($scope: any, $injector: any);
+    targetBlur(): void;
+    getTextValues(metricFindResult: any): any;
+    getCollapsedText(): string;
+    validateTarget(): any;
+}
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js
new file mode 100644
index 0000000..5b5c4a9
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js
@@ -0,0 +1,152 @@
+"use strict";
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    }
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+exports.__esModule = true;
+///<reference path="../../../headers/common.d.ts" />
+var angular_1 = require("angular");
+var lodash_1 = require("lodash");
+var sdk_1 = require("app/plugins/sdk");
+var AmbariMetricsQueryCtrl = /** @class */ (function (_super) {
+    __extends(AmbariMetricsQueryCtrl, _super);
+    /** @ngInject **/
+    function AmbariMetricsQueryCtrl($scope, $injector) {
+        var _this = _super.call(this, $scope, $injector) || this;
+        _this.targetBlur = function () {
+            this.target.errors = this.validateTarget(this.target);
+            // this does not work so good
+            if (!lodash_1["default"].isEqual(this.oldTarget, this.target) && lodash_1["default"].isEmpty(this.target.errors)) {
+                this.oldTarget = angular_1["default"].copy(this.target);
+                this.get_data();
+            }
+        };
+        _this.getTextValues = function (metricFindResult) {
+            return lodash_1["default"].map(metricFindResult, function (value) { return value.text; });
+        };
+        _this.suggestApps = function (query, callback) {
+            this.datasource.suggestApps(query)
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.suggestClusters = function (query, callback) {
+            this.datasource.suggestClusters(this.target.app)
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.suggestHosts = function (query, callback) {
+            this.datasource.suggestHosts(this.target.app, this.target.cluster)
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.suggestMetrics = function (query, callback) {
+            this.datasource.suggestMetrics(query, this.target.app)
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.suggestTagKeys = function (query, callback) {
+            this.datasource.metricFindQuery('tag_names(' + this.target.metric + ')')
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.suggestTagValues = function (query, callback) {
+            this.datasource.metricFindQuery('tag_values(' + this.target.metric + ',' + this.target.currentTagKey + ')')
+                .then(this.getTextValues)
+                .then(callback);
+        };
+        _this.addTag = function () {
+            if (!this.addTagMode) {
+                this.addTagMode = true;
+                return;
+            }
+            if (!this.target.tags) {
+                this.target.tags = {};
+            }
+            this.target.errors = this.validateTarget(this.target);
+            if (!this.target.errors.tags) {
+                this.target.tags[this.target.currentTagKey] = this.target.currentTagValue;
+                this.target.currentTagKey = '';
+                this.target.currentTagValue = '';
+                this.targetBlur();
+            }
+            this.addTagMode = false;
+        };
+        _this.removeTag = function (key) {
+            delete this.target.tags[key];
+            this.targetBlur();
+        };
+        _this.validateTarget = function (target) {
+            var errs = {};
+            if (target.tags && lodash_1["default"].has(target.tags, target.currentTagKey)) {
+                errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
+            }
+            return errs;
+        };
+        _this.errors = _this.validateTarget(_this.target);
+        _this.aggregators = ['none', 'avg', 'sum', 'min', 'max'];
+        _this.precisions = ['default', 'seconds', 'minutes', 'hours', 'days'];
+        _this.transforms = ['none', 'diff', 'rate'];
+        _this.seriesAggregators = ['none', 'avg', 'sum', 'min', 'max'];
+        if (!_this.target.aggregator) {
+            _this.target.aggregator = 'avg';
+        }
+        _this.precisionInit = function () {
+            if (typeof this.target.precision == 'undefined') {
+                this.target.precision = "default";
+            }
+        };
+        _this.transform = function () {
+            if (typeof this.target.transform == 'undefined') {
+                this.target.transform = "none";
+            }
+        };
+        _this.seriesAggregator = function () {
+            if (typeof $scope.target.seriesAggregator == 'undefined') {
+                this.target.seriesAggregator = "none";
+            }
+        };
+        _this.$watch('target.app', function (newValue) {
+            if (newValue === '') {
+                this.target.metric = '';
+                this.target.hosts = '';
+                this.target.cluster = '';
+            }
+        });
+        if (!_this.target.downsampleAggregator) {
+            _this.target.downsampleAggregator = 'avg';
+        }
+        _this.datasource.getAggregators().then(function (aggs) {
+            this.aggregators = aggs;
+        });
+        return _this;
+    }
+    AmbariMetricsQueryCtrl.templateUrl = 'partials/query.editor.html';
+    return AmbariMetricsQueryCtrl;
+}(sdk_1.QueryCtrl));
+exports.AmbariMetricsQueryCtrl = AmbariMetricsQueryCtrl;
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js.map b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js.map
new file mode 100644
index 0000000..2f80a63
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"query_ctrl.js","sourceRoot":"","sources":["../../../../../public/app/plugins/datasource/ambari-metrics/query_ctrl.ts"],"names":["AmbariMetricsQueryCtrl","AmbariMetricsQueryCtrl.constructor","AmbariMetricsQueryCtrl.targetBlur","AmbariMetricsQueryCtrl.getTextValues","AmbariMetricsQueryCtrl.getCollapsedText","AmbariMetricsQueryCtrl.validateTarget"],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,oDAAoD;;;;;;;;;;;;;;;;;;YAMpD;gBAA4CA,0CAASA;gBAajDA,iBAAiBA;gBACjBA,gCAAYA,MAAMA,EAAEA,SAASA;oBAdjCC,iBAyFCA;oBA1EOA,kBAAMA,MAAMA,EAAEA,SAASA,CAACA,CAACA;oBAEzBA,IAAIA,CAACA,MAAMA,GAAGA,IAAIA,CAACA,cAAcA,EAAEA,CAACA;oBACpCA,IAAIA,CAACA,WAAWA,GAAGA,CAACA,MAAMA,EAACA,KAAKA,EAAEA,KAAKA,EAAEA,KAAKA,EAAEA,KAAKA,CAACA,CAACA;oBACvDA,IAAIA,CAACA,UAAUA,GAAGA,CAACA,SAASA,EAACA,SAASA,EAAEA,SAASA,EAAEA,OAAOA,EAAEA,MAAMA,CAACA,CAACA;oBACpEA,IAAIA,CAACA,UAAUA,GAAGA,CAACA,MAAMA,EAACA,MAAMA,CAACA,CAACA;oBAElCA,EAAEA,CAACA,CAACA,CAACA,IAAIA,CAACA,MAAMA,CAACA,UAAUA,CAACA,CAACA,CAACA;wBAC1BA,IAAIA,CAACA,MAAMA,CAACA,UAAUA,GAAGA,KAAKA,CAACA;oBACnCA,CAACA;oBAEDA,IAAIA,CAACA,aAAaA,GAAGA;wBAClB,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC,CAAC;4BAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;wBACvC,CAAC;oBACJ,CAAC,CAACA;oBAEFA,IAAIA,CAACA,SAASA,GAAGA;wBACd,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,WAAW,CAAC,CAAC,CAAC;4BAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC;wBACpC,CAAC;oBACJ,CAAC,CAACA;oBACFA,MAAMA,CAACA,MAAMA,CAACA,iBAAiBA,EAAEA,UAAUA,QAAQA;wBAC/C,EAAE,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC;4BAClB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;4BAC/B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;wBAClC,CAAC;oBACL,CAAC,CAACA,CAACA;oBAGHA,IAAIA,CAACA,UAAUA,CAACA,cAAcA,EAAEA,CAACA,IAAIA,CAACA,UAACA,IAAIA;wBACvCA,EAAEA,CAACA,CAACA,IAAIA,CAACA,MAAMA,KAAKA,CAACA,CAACA,CAACA,CAACA;4BACpBA,KAAIA,CAACA,WAAWA,GAAGA,IAAIA,CAACA;wBAC5BA,CAACA;oBACLA,CAACA,CAACA,CAACA;oBAGHA,IAAIA,CAACA,cAAcA,GAAGA,UAACA,KAAKA,EAAEA,QAAQA;wBAClCA,KAAIA,CAACA,UAAUA,CAACA,cAAcA,CAACA,KAAKA,EAAEA,KAAIA,CAACA,MAAMA,CAACA,GAAGA,CAACA;6BACjDA,IAAIA,CAACA,KAAIA,CAACA,aAAaA,CAACA;6BACxBA,IAAIA,CAACA,QAAQA,CAACA,CAACA;oBACxBA,CAACA,CAACA;oBAEFA,IAAIA,CAACA,WAAWA,GAAGA,UAACA,KAAKA,EAAEA,QAAQA;wBAC/BA,KAAIA,CAACA,UAAUA,CAACA,WAAWA,CAACA,KAAKA,CAACA;6BAC7BA,IAAIA,CAACA,KAAIA,CAACA,aAAaA,CAACA;6BACxBA,IAAIA,CAACA,QAAQA,CAACA,CAACA;oBACxBA,CAACA,CAACA;oBAEFA,IAAIA,CAACA,YAAYA,GAAGA,UAACA,KAAKA,EAAEA,QAAQA;wBAChCA,KAAIA,CAACA,UAAUA,CAACA,YAAYA,CAACA,KAAKA,EAAEA,KAAIA,CAACA,MAAMA,CAACA,GAAGA,CAACA;6BAC/CA,IAAIA,CAACA,KAAIA,CAACA,aAAaA,CAACA;6BACxBA,IAAIA,CAACA,QAAQA,CAACA,CAACA;oBACxBA,CAACA,CAACA;gBACNA,CAACA;gBAEDD,2CAAUA,GAAVA;oBACIE,IAAIA,CAACA,MAAMA,GAAGA,IAAIA,CAACA,cAAcA,EAAEA,CAACA;oBACpCA,IAAIA,CAACA,OAAOA,EAAEA,CAACA;gBACnBA,CAACA;gBAEDF,8CAAaA,GAAbA,UAAcA,gBAAgBA;oBAC1BG,MAAMA,CAACA,gBAACA,CAACA,GAAGA,CAACA,gBAAgBA,EAAEA,UAASA,KAAKA,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAACA,CAACA;gBAC3EA,CAACA;gBACDH,iDAAgBA,GAAhBA;oBACII,IAAIA,IAAIA,GAAGA,IAAIA,CAACA,MAAMA,CAACA,MAAMA,GAAGA,MAAMA,GAAGA,IAAIA,CAACA,MAAMA,CAACA,GAAGA,CAACA;oBACzDA,MAAMA,CAACA,IAAIA,CAACA;gBAChBA,CAACA;gBAEDJ,+CAAcA,GAAdA;oBACIK,IAAIA,IAAIA,GAAQA,EAAEA,CAACA;oBACnBA,MAAMA,CAACA,IAAIA,CAACA;gBAChBA,CAACA;gBAtFML,kCAAWA,GAAGA,4BAA4BA,CAACA;gBAwFtDA,6BAACA;YAADA,CAACA,AAzFD,EAA4C,eAAS,EAyFpD;YAzFD,2DAyFC,CAAA"}
\ No newline at end of file
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.ts
new file mode 100644
index 0000000..70087b6
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.ts
@@ -0,0 +1,169 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+///<reference path="../../../headers/common.d.ts" />
+
+import angular from 'angular';
+import _ from 'lodash';
+import {QueryCtrl} from "app/plugins/sdk";
+
+export class AmbariMetricsQueryCtrl extends QueryCtrl {
+
+    static templateUrl = 'partials/query.editor.html';
+    aggregators: any;
+    aggregator: any;
+    errors: any;
+    precisions: any;
+    transforms: any;
+    transform: any;
+    precisionInit: any;
+    suggestMetrics: any;
+    suggestApps: any;
+    suggestHosts: any;
+    seriesAggregators: any;
+
+    /** @ngInject **/
+    constructor($scope, $injector) {
+        super($scope, $injector);
+        this.errors = this.validateTarget(this.target);
+        this.aggregators = ['none','avg', 'sum', 'min', 'max'];
+        this.precisions = ['default','seconds', 'minutes', 'hours', 'days'];
+        this.transforms = ['none','diff','rate'];
+        this.seriesAggregators = ['none', 'avg', 'sum', 'min', 'max'];
+
+        if (!this.target.aggregator) {
+            this.target.aggregator = 'avg';
+        }
+        this.precisionInit = function () {
+            if (typeof this.target.precision == 'undefined') {
+                this.target.precision = "default";
+            }
+        };
+        this.transform = function () {
+            if (typeof this.target.transform == 'undefined') {
+                this.target.transform = "none";
+            }
+        };
+        this.seriesAggregator = function () {
+            if (typeof $scope.target.seriesAggregator == 'undefined') {
+                this.target.seriesAggregator = "none";
+            }
+        };
+        this.$watch('target.app', function (newValue) {
+            if (newValue === '') {
+                this.target.metric = '';
+                this.target.hosts = '';
+                this.target.cluster = '';
+            }
+        });
+        if (!this.target.downsampleAggregator) {
+            this.target.downsampleAggregator = 'avg';
+        }
+
+        this.datasource.getAggregators().then(function(aggs) {
+            this.aggregators = aggs;
+        });
+    }
+
+    targetBlur = function() {
+        this.target.errors = this.validateTarget(this.target);
+
+        // this does not work so good
+        if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {
+            this.oldTarget = angular.copy(this.target);
+            this.get_data();
+        }
+    };
+
+    getTextValues = function(metricFindResult) {
+        return _.map(metricFindResult, function(value) { return value.text; });
+    };
+
+    suggestApps = function(query, callback) {
+        this.datasource.suggestApps(query)
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    suggestClusters = function(query, callback) {
+        this.datasource.suggestClusters(this.target.app)
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    suggestHosts = function(query, callback) {
+        this.datasource.suggestHosts(this.target.app, this.target.cluster)
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    suggestMetrics = function(query, callback) {
+        this.datasource.suggestMetrics(query, this.target.app)
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    suggestTagKeys = function(query, callback) {
+        this.datasource.metricFindQuery('tag_names(' + this.target.metric + ')')
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    suggestTagValues = function(query, callback) {
+        this.datasource.metricFindQuery('tag_values(' + this.target.metric + ',' + this.target.currentTagKey + ')')
+            .then(this.getTextValues)
+            .then(callback);
+    };
+
+    addTag = function() {
+        if (!this.addTagMode) {
+            this.addTagMode = true;
+            return;
+        }
+
+        if (!this.target.tags) {
+            this.target.tags = {};
+        }
+
+        this.target.errors = this.validateTarget(this.target);
+
+        if (!this.target.errors.tags) {
+            this.target.tags[this.target.currentTagKey] = this.target.currentTagValue;
+            this.target.currentTagKey = '';
+            this.target.currentTagValue = '';
+            this.targetBlur();
+        }
+
+        this.addTagMode = false;
+    };
+
+    removeTag = function(key) {
+        delete this.target.tags[key];
+        this.targetBlur();
+    };
+
+    validateTarget = function(target) {
+        var errs = {};
+
+        if (target.tags && _.has(target.tags, target.currentTagKey)) {
+            errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
+        }
+
+        return errs;
+    }
+}