Revert "[AMBARI-24665] Migrating grafana plugin for 5.x use."

This reverts commit 4dc1c063bd9e1429b53a2d4265745b87b46787d2.
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
deleted file mode 100644
index 33286c8..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-/// <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
deleted file mode 100644
index 84244ed..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js
+++ /dev/null
@@ -1,34 +0,0 @@
-///<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
deleted file mode 100644
index 8c46be5..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/config_ctrl.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"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/datasource.d.ts b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.d.ts
deleted file mode 100644
index 8bab98c..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.d.ts
+++ /dev/null
@@ -1,20 +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.
- */
-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 e34a1af..e7cd850 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/datasource.js
@@ -16,1201 +16,1077 @@
  * limitations under the License.
  */
 define([
-    'angular',
-    'lodash',
-    'jquery',
-    //'./directives',
-    './query_ctrl'
-  ],
-  function (angular, _) {
-    'use strict';
+      'angular',
+      'lodash',
+      'jquery',
+      './directives',
+      './queryCtrl'
+    ],
+    function (angular, _) {
+      'use strict';
 
+      var module = angular.module('grafana.services');
 
-    /**
-     * 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;
+      module.factory('AmbariMetricsDatasource', function ($q, backendSrv, templateSrv) {
+        /**
+         * AMS Datasource Constructor
+         */
+        function AmbariMetricsDatasource(datasource) {
+          this.name = datasource.name;
+          this.url = datasource.url;
+          this.initMetricAppidMapping();
         }
-        if (this.basicAuth) {
-          options.headers = options.headers || {};
-          options.headers.Authorization = this.basicAuth;
-        }
+        var allMetrics = {};
+        var appIds = [];
 
-        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);
-          });
-      };
-      this.initMetricAppidMapping();
-
-
-
-      /**
-       * 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 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)]);
-              }
-            }
-            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);
+        //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);
                 });
-                // 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 = '';
+              });
+              //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);
+            });
+        };
+
+        /**
+         * 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: []
               }
-              if (data.appid.indexOf('ambari_server') === 0) {
-                alias = data.metricname;
-                aliasSuffix = '';
+            };
+          };
+          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 + aliasSuffix,
+                target: alias + hostLegend,
                 datapoints: []
               };
-              for (var k in data.metrics) {
-                if (data.metrics.hasOwnProperty(k)) {
-                  timeSeries.datapoints.push([data.metrics[k], (k - k % 1000)]);
+              for (var k in metricData){
+                if (metricData.hasOwnProperty(k)) {
+                  timeSeries.datapoints.push([metricData[k], (k - k % 1000)]);
                 }
               }
-              if ((user !== '*') || (totalCountFlag)) {
-                series.push(timeSeries);
-              }
-            });
-            return $q.when({data: series});
+              series.push(timeSeries);
+              return $q.when({data: series});
+            };
           };
-        };
-        var getHostAppIdData = function (target) {
-          var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
+          // 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 + 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});
+            };
+          };
+          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 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 getKafkaAppIdData = 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.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.nnMetric + metricTransform + instanceId
+            + metricAggregator + '&appId=namenode&startTime=' + from + '&endTime=' + to + precision + seriesAggregator }).then(
+              allHostMetricsData(target)
+            );
+          };
 
-          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 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 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)
+            );
+          };
 
-        // 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='
+            // 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='
             + 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.sDataSourceMetric + metricTransform + instanceId
+                          + metricAggregator + '&appId=druid&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)
-          );
-        };
+          // 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)
-          );
-        };
-
-        // 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);
+          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);
                 }));
               });
             }
-          }
-          // 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));
+            // 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);
+                }));
+              });
             }
-            _.forEach(splitTables, function (table) {
-              metricsPromises.push(_.map(options.targets, function (target) {
-                var hbMetric = [];
-                _.map(table, function (tableMetric) {
-                  hbMetric.push(target.metric.replace('*', tableMetric));
+            //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);
+                    }));
                 });
-                var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
-                hbMetric = _.map(hbMetric, function (tbl) {
-                  return tbl + metricTransform + '._' + target.aggregator;
+            }
+
+            //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);
+                    }));
                 });
-                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 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 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 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 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 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);
+            //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 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;
             }
-          }
-          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);
+
+            //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);
+                }));
+              });
             }
-          });
-        }
-
-        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];
+            // 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;
                   }
-                } 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);
-      };
-
-      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});
+              }
+              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);
+              }
+            });
           }
-          return $q.when(clusters);
-        });
-      };
 
-      /**
-       * 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.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.
+         */
+        AmbariMetricsDatasource.prototype.listSeries = function (query) {
+          // wrap in regex
+          if (query && query.length > 0 && query[0] !== '/') {
+            query = '/' + query + '/';
+          }
+          return $q.when([]);
+        };
+
+        /**
+         * 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" };
+            }
+          });
+        };
+
+        /**
+         * 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);
+        };
+
+        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]});
+                }
               }
             }
+            return $q.when(hosts);
+          });
+        };
+
+        /**
+         * AMS Datasource Aggregators.
+         */
+        var aggregatorsPromise = null;
+        AmbariMetricsDatasource.prototype.getAggregators = function () {
+          if (aggregatorsPromise) {
+            return aggregatorsPromise;
           }
-          return $q.when(hosts);
-        });
-      };
-
-      /**
-       * AMS Datasource Aggregators.
-       */
-      var aggregatorsPromise = null;
-      this.getAggregators = function () {
-        if (aggregatorsPromise) {
+          aggregatorsPromise = $q.when([
+            'none','avg', 'sum', 'min', 'max'
+          ]);
           return aggregatorsPromise;
-        }
-        aggregatorsPromise = $q.when([
-          'none', 'avg', 'sum', 'min', 'max'
-        ]);
-        return aggregatorsPromise;
-      };
-    };
+        };
 
-    return {
-      AmbariMetricsDatasource: AmbariMetricsDatasource
-    };
-
-
-  });
-
+        return AmbariMetricsDatasource;
+      });
+    }
+);
diff --git a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
index 087533c..aade7d7 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/directives.js
@@ -34,4 +34,3 @@
   });
 
 });
-
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
deleted file mode 100644
index 358e42e..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/ams-screenshot.png
+++ /dev/null
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
deleted file mode 100644
index 0f90391..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo-sm.png
+++ /dev/null
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
deleted file mode 100644
index 07412bd..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-logo.png
+++ /dev/null
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
deleted file mode 100644
index 7ce8965..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/img/apache-ambari-project.png
+++ /dev/null
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
deleted file mode 100644
index 3e12e14..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.d.ts
+++ /dev/null
@@ -1,21 +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.
- */
-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
deleted file mode 100644
index ebc4f8a..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js
+++ /dev/null
@@ -1,21 +0,0 @@
-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
deleted file mode 100644
index 5bdb60e..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"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
deleted file mode 100644
index 137e7c7..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/module.ts
+++ /dev/null
@@ -1,26 +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.
- */
-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
deleted file mode 100644
index e69de29..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/annotations.editor.html
+++ /dev/null
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 d4ad4b3..360c15c 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/config.html
@@ -15,4 +15,5 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<datasource-http-settings current="ctrl.current"></datasource-http-settings>
\ No newline at end of file
+<div ng-include="httpConfigPartialSrc"></div>
+<br>
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 e0f1461..7e78cc0 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,98 +15,162 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<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>
+<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>
 
-    <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">
+        <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>
 
+    <ul class="tight-form-list" role="menu">
 
-    <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">
+        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">
-        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">
+            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>
-	<div class="gf-form-inline">
+        <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 class="gf-form">
-    	<label class="gf-form-label query-keyword width-8">
+        <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">
             Alias
-        </label>
-            <input type="text" class="gf-form-input input-large"
-                   ng-model="ctrl.target.alias"
+        </li>
+        <li>
+            <input type="text" class="tight-form-input input-large"
+                   ng-model="target.alias"
                    spellcheck='false'
                    placeholder="series alias"
                    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">
+                   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>
-    </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>
+        <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 class="gf-form">
-    	<label class="gf-form-label query-keyword width-8">
+        <li class="tight-form-item tight-form-align">
             Precision
-        </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()">
+        </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()">
             </select>
-    </div>
-        <div class="clearfix"></div>
+        </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>
-</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
new file mode 100644
index 0000000..e58ca64
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/partials/query.options.html
@@ -0,0 +1,42 @@
+<!--
+  ~ 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 643da57..5226ae7 100644
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/plugin.json
@@ -1,21 +1,14 @@
 {
-  "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",
+  "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"
   },
-}
+
+  "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
new file mode 100644
index 0000000..02b5813
--- /dev/null
+++ b/ambari-metrics/ambari-metrics-grafana/ambari-metrics/queryCtrl.js
@@ -0,0 +1,160 @@
+/**
+ * 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
deleted file mode 100644
index 83363f7..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.d.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/// <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
deleted file mode 100644
index 5b5c4a9..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js
+++ /dev/null
@@ -1,152 +0,0 @@
-"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
deleted file mode 100644
index 2f80a63..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"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
deleted file mode 100644
index 70087b6..0000000
--- a/ambari-metrics/ambari-metrics-grafana/ambari-metrics/query_ctrl.ts
+++ /dev/null
@@ -1,169 +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.
- */
-
-///<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;
-    }
-}