You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ja...@apache.org on 2015/04/22 22:48:39 UTC

[1/3] ambari git commit: AMBARI-10648. Integrate Heatmap pages with widget and widget layout API. (jaimin)

Repository: ambari
Updated Branches:
  refs/heads/trunk a93a31265 -> 9639005f6


http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed_test.js
deleted file mode 100644
index 4d8a847..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed_test.js
+++ /dev/null
@@ -1,128 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed');
-
-describe('App.MainChartHeatmapYarnResourceUsedMetric', function () {
-
-  var mainChartHeatmapYarnResourceUsedMetric = App.MainChartHeatmapYarnResourceUsedMetric.create({});
-
-  describe('#metricMapper', function () {
-    var tests = [
-      {
-        m: 'Correct JSON #1',
-        i: {
-          ServiceComponentInfo: {
-            cluster_name: "c1",
-            component_name: "NODEMANAGER",
-            service_name: "YARN"
-          },
-          host_components: [{
-            HostRoles: {
-              cluster_name: "c1",
-              component_name: "NODEMANAGER",
-              host_name: "host1"
-            },
-            metrics: {
-              yarn: {
-                AllocatedGB: 0,
-                AvailableGB: 2
-              }
-            }
-          }]
-        },
-        e: {
-          length: 1,
-          val: '0.0',
-          host: 'host1'
-        }
-      },
-      {
-        m: 'Correct JSON #2',
-        i: {
-          ServiceComponentInfo: {
-            cluster_name: "c1",
-            component_name: "NODEMANAGER",
-            service_name: "YARN"
-          },
-          host_components: [{
-            HostRoles: {
-              cluster_name: "c1",
-              component_name: "NODEMANAGER",
-              host_name: "host1"
-            },
-            metrics: {
-              yarn: {
-                AllocatedGB: 1,
-                AvailableGB: 2
-              }
-            }
-          }]
-        },
-        e: {
-          length: 1,
-          val: '33.3',
-          host: 'host1'
-        }
-      },
-      {
-        m: 'Correct JSON #3',
-        i: {
-          ServiceComponentInfo: {
-            cluster_name: "c1",
-            component_name: "NODEMANAGER",
-            service_name: "YARN"
-          },
-          host_components: [{
-            HostRoles: {
-              cluster_name: "c1",
-              component_name: "NODEMANAGER",
-              host_name: "host1"
-            },
-            metrics: {
-              yarn: {
-                AllocatedGB: 0,
-                AvailableGB: 0
-              }
-            }
-          }]
-        },
-        e: {
-          length: 1,
-          val: 'Unknown',
-          host: 'host1'
-        }
-      }
-    ];
-    tests.forEach(function(test) {
-      it(test.m, function () {
-        var result = mainChartHeatmapYarnResourceUsedMetric.metricMapper(test.i),
-          length = Em.keys(result).length;
-        expect(length).to.equal(test.e.length);
-        if (test.e.host) {
-          expect(result.hasOwnProperty(test.e.host)).to.equal(true);
-          expect(result[test.e.host]).to.equal(test.e.val);
-        }
-      });
-    });
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_test.js
deleted file mode 100644
index d8744cd..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_test.js
+++ /dev/null
@@ -1,115 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn');
-
-describe('App.MainChartHeatmapYarnMetrics', function () {
-
-  var tests = [
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "memHeapUsedM" : 10
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 10},
-      m: 'One host_component'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "memHeapUsedM" : 10
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "memHeapUsedM" : 20
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 10, 'dev02.hortonworks.com': 20},
-      m: 'Two host_components'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "memHeapUsedM" : 10
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 10},
-      m: 'Two host_components, one without metric'
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapYarnMetrics = App.MainChartHeatmapYarnMetrics.create();
-    mainChartHeatmapYarnMetrics.set('defaultMetric', 'metrics.jvm.memHeapUsedM');
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapYarnMetrics.metricMapper(test.json);
-        expect(r).to.eql(test.result);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_test.js b/ambari-web/test/controllers/main/charts/heatmap_test.js
index 399a34c..56c672c 100644
--- a/ambari-web/test/controllers/main/charts/heatmap_test.js
+++ b/ambari-web/test/controllers/main/charts/heatmap_test.js
@@ -47,41 +47,33 @@ describe('MainChartsHeatmapController', function () {
   });
 
   describe('#showHeatMapMetric()', function () {
-    var controller = App.MainChartsHeatmapController.create({
-      allMetrics: [],
-      selectedMetric: Ember.Object.create({maximumValue: 100}),
-      loadMetrics: function () {
-      }
+    beforeEach(function () {
+      sinon.stub(App.ajax, 'send', function () {
+        return {
+          done: function (callback) {
+            callback();
+          }
+        }
+      });
     });
-    controller.set("selectedMetric", 100);
-    it('should not set selectedMetric event.context if it is not defined', function () {
-      controller.showHeatMapMetric({});
-      expect(controller.get('selectedMetric')).to.equal(100);
-    });
-    it('should set selectedMetric event.context if it is defined', function () {
-      controller.showHeatMapMetric({context: 5});
-      expect(controller.get('selectedMetric')).to.equal(5);
+
+    afterEach(function () {
+      App.ajax.send.restore();
     });
-  });
 
-  describe('#loadMetrics()', function () {
     var controller = App.MainChartsHeatmapController.create({
-      testPassed: false,
-      allMetrics: [],
-      inputMaximum: 10
+      activeWidgetLayout: Em.Object.create({
+        displayName: 'widget',
+        id: '1',
+        scope: 'CLUSTER',
+        layoutName: 'defualt_layout',
+        sectionName: 'default_section'
+      })
     });
-    controller.set('selectedMetric', Ember.Object.create({
-      maximumValue: 100,
-      refreshHostSlots: function () {
-        controller.set('testPassed', true);
-      }
-    }));
-    controller.loadMetrics();
-    it('should set inputMaximum as selectedMetric.maximumValue', function () {
-      expect(controller.get('inputMaximum')).to.equal(100);
-    });
-    it('should call refreshHostSlots from selectedMetric', function () {
-      expect(controller.get('testPassed')).to.equal(true);
+
+    it('should call App.ajax', function () {
+      controller.showHeatMapMetric({context:{id: 2}});
+      expect(App.ajax.send.called).to.be.true;
     });
   });
 


[2/3] ambari git commit: AMBARI-10648. Integrate Heatmap pages with widget and widget layout API. (jaimin)

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/mixins/common/widget_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widget_mixin.js b/ambari-web/app/mixins/common/widget_mixin.js
deleted file mode 100644
index e59fb20..0000000
--- a/ambari-web/app/mixins/common/widget_mixin.js
+++ /dev/null
@@ -1,426 +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.
- */
-
-var App = require('app');
-
-App.WidgetMixin = Ember.Mixin.create({
-
-  /**
-   * @type {RegExp}
-   * @const
-   */
-  EXPRESSION_REGEX: /\$\{([\w\s\.\,\+\-\*\/\(\)\:\=\[\]]*)\}/g,
-
-  /**
-   * @type {RegExp}
-   * @const
-   */
-  MATH_EXPRESSION_REGEX: /^[\d\s\+\-\*\/\(\)\.]+$/,
-
-  /**
-   * @type {RegExp}
-   * @const
-   */
-  VALUE_NAME_REGEX: /[\w\.\,\:\=\[\]]+/g,
-
-  /**
-   * common metrics container
-   * @type {Array}
-   */
-  metrics: [],
-
-  /**
-   * @type {boolean}
-   */
-  isLoaded: false,
-
-  /**
-   * @type {App.Widget}
-   * @default null
-   */
-  content: null,
-
-  beforeRender: function () {
-    this.loadMetrics();
-  },
-
-
-  /**
-   * load metrics
-   */
-  loadMetrics: function () {
-    var requestData = this.getRequestData(this.get('content.metrics')),
-      request,
-      requestCounter = 0,
-      self = this;
-
-    for (var i in requestData) {
-      request = requestData[i];
-      requestCounter++;
-      if (request.host_component_criteria) {
-        this.getHostComponentMetrics(request).always(function () {
-          requestCounter--;
-          if (requestCounter === 0) self.onMetricsLoaded();
-        });
-      } else {
-        this.getServiceComponentMetrics(request).complete(function () {
-          requestCounter--;
-          if (requestCounter === 0) self.onMetricsLoaded();
-        });
-      }
-    }
-  },
-
-  /**
-   * get data formatted for request
-   * @param {Array} metrics
-   */
-  getRequestData: function (metrics) {
-    var requestsData = {};
-    if (metrics) {
-      metrics.forEach(function (metric, index) {
-        var key;
-        if (metric.host_component_criteria) {
-          this.tweakHostComponentCriteria(metric);
-          key = metric.service_name + '_' + metric.component_name + '_' + metric.host_component_criteria;
-        } else {
-          key = metric.service_name + '_' + metric.component_name;
-        }
-        var requestMetric = $.extend({}, metric);
-
-        if (requestsData[key]) {
-          requestsData[key]["metric_paths"].push(requestMetric["metric_path"]);
-        } else {
-          requestMetric["metric_paths"] = [requestMetric["metric_path"]];
-          delete requestMetric["metric_path"];
-          requestsData[key] = requestMetric;
-        }
-      }, this);
-    }
-    return requestsData;
-  },
-
-  /**
-   * Tweak necessary host component criteria
-   * NameNode HA host component criteria is applicable only in HA mode
-   */
-  tweakHostComponentCriteria: function (metric) {
-    switch (metric.component_name) {
-      case 'NAMENODE':
-        if (metric.host_component_criteria === 'host_components/metrics/dfs/FSNamesystem/HAState=active') {
-          //if (metric.host_component_criteria)
-          var hdfs = App.HDFSService.find().objectAt(0);
-          var activeNNHostName = !hdfs.get('snameNode') && hdfs.get('activeNameNode');
-          if (!activeNNHostName) {
-            metric.host_component_criteria = 'host_components/HostRoles/component_name=NAMENODE';
-          }
-        }
-        break;
-    }
-  },
-
-  /**
-   * make GET call to server in order to fetch service-component metrics
-   * @param {object} request
-   * @returns {$.ajax}
-   */
-  getServiceComponentMetrics: function (request) {
-    return App.ajax.send({
-      name: 'widgets.serviceComponent.metrics.get',
-      sender: this,
-      data: {
-        serviceName: request.service_name,
-        componentName: request.component_name,
-        metricPaths: request.metric_paths.join(',')
-      },
-      success: 'getMetricsSuccessCallback'
-    });
-  },
-
-  /**
-   * make GET call to server in order to fetch service-component metrics
-   * @param {object} request
-   * @returns {$.Deferred}
-   */
-  getHostComponentMetrics: function (request) {
-    var dfd;
-    var self = this;
-    dfd = $.Deferred();
-    this.getHostComponentName(request).done(function (data) {
-      if (data) {
-        request.host_name = data.host_components[0].HostRoles.host_name;
-        App.ajax.send({
-          name: 'widgets.hostComponent.metrics.get',
-          sender: self,
-          data: {
-            componentName: request.component_name,
-            hostName: request.host_name,
-            metricPaths: request.metric_paths.join(',')
-          }
-        }).done(function(metricData) {
-          self.getMetricsSuccessCallback(metricData);
-          dfd.resolve();
-        }).fail(function(data){
-          dfd.reject();
-        });
-      }
-    }).fail(function(data){
-      dfd.reject();
-    });
-    return dfd.promise();
-  },
-
-  /**
-   * make GET call to server in order to fetch host-component names
-   * @param {object} request
-   * @returns {$.ajax}
-   */
-  getHostComponentName: function (request) {
-    return App.ajax.send({
-      name: 'widgets.hostComponent.get.hostName',
-      sender: this,
-      data: {
-        serviceName: request.service_name,
-        componentName: request.component_name,
-        metricPaths: request.metric_paths.join(','),
-        hostComponentCriteria: request.host_component_criteria
-      }
-    });
-  },
-
-  /**
-   * callback on getting aggregated metrics and host component metrics
-   * @param data
-   */
-  getMetricsSuccessCallback: function (data) {
-    var metrics = [];
-
-    this.get('content.metrics').forEach(function (_metric) {
-      if (!Em.isNone(Em.get(data, _metric.metric_path.replace(/\//g, '.')))) {
-        _metric.data = Em.get(data, _metric.metric_path.replace(/\//g, '.'));
-        this.get('metrics').pushObject(_metric);
-      }
-    }, this);
-  },
-
-
-  /**
-   * callback on metrics loaded
-   */
-  onMetricsLoaded: function () {
-    var self = this;
-    this.set('isLoaded', true);
-    this.drawWidget();
-    setTimeout(function () {
-      self.loadMetrics();
-    }, App.contentUpdateInterval);
-  },
-
-
-  /**
-   * draw widget
-   */
-  drawWidget: function () {
-    if (this.get('isLoaded')) {
-      this.calculateValues();
-      this.set('value', this.get('content.values')[0] && this.get('content.values')[0].computedValue);
-    }
-  },
-
-  /**
-   * calculate series datasets for graph widgets
-   */
-  calculateValues: function () {
-    var metrics = this.get('metrics');
-    var displayUnit = this.get('content.properties.display_unit');
-
-    this.get('content.values').forEach(function (value) {
-      var computeExpression = this.computeExpression(this.extractExpressions(value), metrics);
-      value.computedValue = value.value.replace(this.get('EXPRESSION_REGEX'), function (match) {
-        return (!Em.isNone(computeExpression[match])) ? computeExpression[match] + (displayUnit || "") : Em.I18n.t('common.na');
-      });
-    }, this);
-  },
-
-
-  /**
-   * extract expressions
-   * Example:
-   *  input: "${a/b} equal ${b+a}"
-   *  expressions: ['a/b', 'b+a']
-   *
-   * @param {object} input
-   * @returns {Array}
-   */
-  extractExpressions: function (input) {
-    var pattern = this.get('EXPRESSION_REGEX'),
-      expressions = [],
-      match;
-
-    while (match = pattern.exec(input.value)) {
-      expressions.push(match[1]);
-    }
-    return expressions;
-  },
-
-
-  /**
-   * compute expression
-   * @param expressions
-   * @param metrics
-   * @returns {object}
-   */
-  computeExpression: function (expressions, metrics) {
-    var result = {};
-
-    expressions.forEach(function (_expression) {
-      var validExpression = true;
-      var value = "";
-
-      //replace values with metrics data
-      var beforeCompute = _expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
-        if (metrics.someProperty('name', match)) {
-          return metrics.findProperty('name', match).data;
-        } else {
-          validExpression = false;
-          console.warn('Metrics not found to compute expression');
-        }
-      });
-
-      if (validExpression) {
-        //check for correct math expression
-        validExpression = this.get('MATH_EXPRESSION_REGEX').test(beforeCompute);
-        !validExpression && console.warn('Value is not correct mathematical expression');
-      }
-
-      result['${' + _expression + '}'] = (validExpression) ? Number(window.eval(beforeCompute)).toString() : value;
-    }, this);
-    return result;
-  },
-
-  /*
-   * make call when clicking on "remove icon" on widget
-   */
-  hideWidget: function (event) {
-    this.get('controller').hideWidget(
-      {
-        context: Em.Object.create({
-          id: event.context
-        })
-      }
-    );
-  },
-
-  /*
-   * make call when clicking on "clone icon" on widget
-   */
-  cloneWidget: function (event) {
-    var self = this;
-    return App.showConfirmationPopup(
-      function() {
-        self.postWidgetDefinition();
-      },
-      Em.I18n.t('widget.clone.body').format(self.get('content.displayName')),
-      null,
-      null,
-      Em.I18n.t('common.clone')
-    );
-  },
-
-  /**
-   * collect all needed data to create new widget
-   * @returns {{WidgetInfo: {widget_name: *, display_name: *, widget_type: *, description: *, scope: *, metrics: *, values: *, properties: *}}}
-   */
-  collectWidgetData: function () {
-    return {
-      WidgetInfo: {
-        widget_name: this.get('content.widgetName'),
-        display_name: this.get('content.displayName'),
-        widget_type: this.get('content.widgetType'),
-        description: this.get('content.widgetDescription'),
-        scope: this.get('content.scope'),
-        "metrics": this.get('content.metrics').map(function (metric) {
-          return {
-            "name": metric.name,
-            "service_name": metric.serviceName,
-            "component_name": metric.componentName,
-            "metric_path": metric.metric_path,
-            "category": metric.category
-          }
-        }),
-        values: this.get('content.values'),
-        properties: this.get('content.properties')
-      }
-    };
-  },
-
-  /**
-   * post widget definition to server
-   * @returns {$.ajax}
-   */
-  postWidgetDefinition: function () {
-    return App.ajax.send({
-      name: 'widgets.wizard.add',
-      sender: this,
-      data: {
-        data: this.collectWidgetData()
-      },
-      success: 'postWidgetDefinitionSuccessCallback'
-    });
-  },
-
-  postWidgetDefinitionSuccessCallback: function() {
-
-  },
-
-  /*
-   * make call when clicking on "edit icon" on widget
-   */
-  editWidget: function (event) {
-    this.get('controller').editWidget(this.get('content'));
-  }
-
-});
-App.WidgetPreviewMixin = Ember.Mixin.create({
-  beforeRender: Em.K,
-  isLoaded: true,
-  metrics: [],
-  content: Em.Object.create({
-    widgetName: 'mock-widget',
-    values: []
-  }),
-  drawWidget: function () {
-    this.loadMetrics();
-    this.get('content').setProperties({
-      'values': this.get('controller.widgetValues'),
-      'properties': this.get('controller.widgetProperties'),
-      'displayName': this.get('controller.widgetName')
-    });
-    this._super();
-  }.observes('controller.widgetProperties', 'controller.widgetValues', 'controller.widgetMetrics', 'controller.widgetName'),
-  loadMetrics: function () {
-    var metrics = [];
-    this.get('controller.widgetMetrics').forEach(function (metric) {
-      metrics.push({
-        name: metric.name,
-        data: this.get('MOCK_VALUE')
-      });
-    }, this);
-    this.set('metrics', metrics);
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/mixins/common/widgets/widget_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widgets/widget_mixin.js b/ambari-web/app/mixins/common/widgets/widget_mixin.js
new file mode 100644
index 0000000..8e5e110
--- /dev/null
+++ b/ambari-web/app/mixins/common/widgets/widget_mixin.js
@@ -0,0 +1,506 @@
+/**
+ * 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 App = require('app');
+
+App.WidgetMixin = Ember.Mixin.create({
+
+  /**
+   * @type {RegExp}
+   * @const
+   */
+  EXPRESSION_REGEX: /\$\{([\w\s\.\,\+\-\*\/\(\)\:\=\[\]]*)\}/g,
+
+  /**
+   * @type {RegExp}
+   * @const
+   */
+  MATH_EXPRESSION_REGEX: /^[\d\s\+\-\*\/\(\)\.]+$/,
+
+  /**
+   * @type {RegExp}
+   * @const
+   */
+  VALUE_NAME_REGEX: /[\w\.\,\:\=\[\]]+/g,
+
+  /**
+   * common metrics container
+   * @type {Array}
+   */
+  metrics: [],
+
+  /**
+   * @type {boolean}
+   */
+  isLoaded: false,
+
+  /**
+   * @type {App.Widget}
+   * @default null
+   */
+  content: null,
+
+  beforeRender: function () {
+    this.get('metrics').clear();
+    this.loadMetrics();
+  },
+
+
+  /**
+   * load metrics
+   */
+  loadMetrics: function () {
+    var requestData = this.getRequestData(this.get('content.metrics')),
+      request,
+      requestCounter = 0,
+      self = this;
+
+    for (var i in requestData) {
+      request = requestData[i];
+      requestCounter++;
+      if (this.get('content.widgetType') === 'HEATMAP'){
+        if (request.service_name === 'STACK') {
+          this.getHostsMetrics(request).complete(function () {
+            requestCounter--;
+            if (requestCounter === 0) self.onMetricsLoaded();
+          });
+        } else {
+          this.getHostComponentsMetrics(request).complete(function () {
+            requestCounter--;
+            if (requestCounter === 0) self.onMetricsLoaded();
+          });
+        }
+      } else if (request.host_component_criteria) {
+        this.getHostComponentMetrics(request).always(function () {
+          requestCounter--;
+          if (requestCounter === 0) self.onMetricsLoaded();
+        });
+      } else {
+        this.getServiceComponentMetrics(request).complete(function () {
+          requestCounter--;
+          if (requestCounter === 0) self.onMetricsLoaded();
+        });
+      }
+    }
+  },
+
+  /**
+   * get data formatted for request
+   * @param {Array} metrics
+   */
+  getRequestData: function (metrics) {
+    var requestsData = {};
+    if (metrics) {
+      metrics.forEach(function (metric, index) {
+        var key;
+        if (metric.host_component_criteria) {
+          this.tweakHostComponentCriteria(metric);
+          key = metric.service_name + '_' + metric.component_name + '_' + metric.host_component_criteria;
+        } else {
+          key = metric.service_name + '_' + metric.component_name;
+        }
+        var requestMetric = $.extend({}, metric);
+
+        if (requestsData[key]) {
+          requestsData[key]["metric_paths"].push(requestMetric["metric_path"]);
+        } else {
+          requestMetric["metric_paths"] = [requestMetric["metric_path"]];
+          delete requestMetric["metric_path"];
+          requestsData[key] = requestMetric;
+        }
+      }, this);
+    }
+    return requestsData;
+  },
+
+  /**
+   * Tweak necessary host component criteria
+   * NameNode HA host component criteria is applicable only in HA mode
+   */
+  tweakHostComponentCriteria: function (metric) {
+    switch (metric.component_name) {
+      case 'NAMENODE':
+        if (metric.host_component_criteria === 'host_components/metrics/dfs/FSNamesystem/HAState=active') {
+          //if (metric.host_component_criteria)
+          var hdfs = App.HDFSService.find().objectAt(0);
+          var activeNNHostName = !hdfs.get('snameNode') && hdfs.get('activeNameNode');
+          if (!activeNNHostName) {
+            metric.host_component_criteria = 'host_components/HostRoles/component_name=NAMENODE';
+          }
+        }
+        break;
+    }
+  },
+
+  /**
+   * make GET call to server in order to fetch service-component metrics
+   * @param {object} request
+   * @returns {$.ajax}
+   */
+  getServiceComponentMetrics: function (request) {
+    return App.ajax.send({
+      name: 'widgets.serviceComponent.metrics.get',
+      sender: this,
+      data: {
+        serviceName: request.service_name,
+        componentName: request.component_name,
+        metricPaths: request.metric_paths.join(',')
+      },
+      success: 'getMetricsSuccessCallback'
+    });
+  },
+
+  /**
+   * make GET call to server in order to fetch specifc host-component metrics
+   * @param {object} request
+   * @returns {$.Deferred}
+   */
+  getHostComponentMetrics: function (request) {
+    var dfd;
+    var self = this;
+    dfd = $.Deferred();
+    this.getHostComponentName(request).done(function (data) {
+      if (data) {
+        request.host_name = data.host_components[0].HostRoles.host_name;
+        App.ajax.send({
+          name: 'widgets.hostComponent.metrics.get',
+          sender: self,
+          data: {
+            componentName: request.component_name,
+            hostName: request.host_name,
+            metricPaths: request.metric_paths.join(',')
+          }
+        }).done(function(metricData) {
+          self.getMetricsSuccessCallback(metricData);
+          dfd.resolve();
+        }).fail(function(data){
+          dfd.reject();
+        });
+      }
+    }).fail(function(data){
+      dfd.reject();
+    });
+    return dfd.promise();
+  },
+
+
+
+  /**
+   * make GET call to server in order to fetch host-component names
+   * @param {object} request
+   * @returns {$.ajax}
+   */
+  getHostComponentName: function (request) {
+    return App.ajax.send({
+      name: 'widgets.hostComponent.get.hostName',
+      sender: this,
+      data: {
+        serviceName: request.service_name,
+        componentName: request.component_name,
+        metricPaths: request.metric_paths.join(','),
+        hostComponentCriteria: request.host_component_criteria
+      }
+    });
+  },
+
+
+  /**
+   * callback on getting aggregated metrics and host component metrics
+   * @param data
+   */
+  getMetricsSuccessCallback: function (data) {
+    var metrics = [];
+
+    this.get('content.metrics').forEach(function (_metric) {
+      if (!Em.isNone(Em.get(data, _metric.metric_path.replace(/\//g, '.')))) {
+        _metric.data = Em.get(data, _metric.metric_path.replace(/\//g, '.'));
+        this.get('metrics').pushObject(_metric);
+      }
+    }, this);
+  },
+
+  /**
+   * make GET call to get host component metrics accross
+   * @param {object} request
+   * @return {$.ajax}
+   */
+  getHostComponentsMetrics: function(request) {
+    request.metric_paths.forEach(function(_metric,index){
+      request.metric_paths[index] = "host_components/" + _metric;
+    });
+    return App.ajax.send({
+      name: 'widgets.serviceComponent.metrics.get',
+      sender: this,
+      data: {
+        serviceName: request.service_name,
+        componentName: request.component_name,
+        metricPaths: request.metric_paths.join(',')
+      },
+      success: 'getHostComponentsMetricsSuccessCallback'
+    });
+  },
+
+
+  getHostComponentsMetricsSuccessCallback: function(data) {
+    var metrics = this.get('content.metrics');
+    data.host_components.forEach(function(item){
+      metrics.forEach(function (_metric) {
+        if (!Em.isNone(Em.get(item, _metric.metric_path.replace(/\//g, '.')))) {
+          var metric = $.extend({},_metric,true);
+          metric.data =  Em.get(item, _metric.metric_path.replace(/\//g, '.'));
+          metric.hostName = item.HostRoles.host_name;
+          this.get('metrics').pushObject(metric);
+        }
+      }, this);
+    },this);
+  },
+
+  getHostsMetrics: function(request) {
+    return App.ajax.send({
+      name: 'widgets.hosts.metrics.get',
+      sender: this,
+      data: {
+        metricPaths: request.metric_paths.join(',')
+      },
+      success: 'getHostsMetricsSuccessCallback'
+    });
+  },
+
+  getHostsMetricsSuccessCallback: function(data) {
+    var metrics = this.get('content.metrics');
+    data.items.forEach(function(item){
+      metrics.forEach(function (_metric,index) {
+        if (!Em.isNone(Em.get(item, _metric.metric_path.replace(/\//g, '.')))) {
+          var metric = $.extend({},_metric,true);
+          metric.data =  Em.get(item, _metric.metric_path.replace(/\//g, '.'));
+          metric.hostName = item.Hosts.host_name;
+          this.get('metrics').pushObject(metric);
+        }
+      }, this);
+    },this);
+  },
+
+  /**
+   * callback on metrics loaded
+   */
+  onMetricsLoaded: function () {
+    var self = this;
+    this.set('isLoaded', true);
+    this.drawWidget();
+    setTimeout(function () {
+      self.loadMetrics();
+    }, App.contentUpdateInterval);
+  },
+
+
+  /**
+   * draw widget
+   */
+  drawWidget: function () {
+    if (this.get('isLoaded')) {
+      this.calculateValues();
+      this.set('value', this.get('content.values')[0] && this.get('content.values')[0].computedValue);
+    }
+  },
+
+  /**
+   * calculate series datasets for graph widgets
+   */
+  calculateValues: function () {
+    var metrics = this.get('metrics');
+    var displayUnit = this.get('content.properties.display_unit');
+
+    this.get('content.values').forEach(function (value) {
+      var computeExpression = this.computeExpression(this.extractExpressions(value), metrics);
+      value.computedValue = value.value.replace(this.get('EXPRESSION_REGEX'), function (match) {
+        return (!Em.isNone(computeExpression[match])) ? computeExpression[match] + (displayUnit || "") : Em.I18n.t('common.na');
+      });
+    }, this);
+  },
+
+
+  /**
+   * extract expressions
+   * Example:
+   *  input: "${a/b} equal ${b+a}"
+   *  expressions: ['a/b', 'b+a']
+   *
+   * @param {object} input
+   * @returns {Array}
+   */
+  extractExpressions: function (input) {
+    var pattern = this.get('EXPRESSION_REGEX'),
+      expressions = [],
+      match;
+
+    while (match = pattern.exec(input.value)) {
+      expressions.push(match[1]);
+    }
+    return expressions;
+  },
+
+
+  /**
+   * compute expression
+   * @param expressions
+   * @param metrics
+   * @returns {object}
+   */
+  computeExpression: function (expressions, metrics) {
+    var result = {};
+
+    expressions.forEach(function (_expression) {
+      var validExpression = true;
+      var value = "";
+
+      //replace values with metrics data
+      var beforeCompute = _expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
+        if (window.isNaN(match)) {
+          if (metrics.someProperty('name', match)) {
+            return metrics.findProperty('name', match).data;
+          } else {
+            validExpression = false;
+            console.error('Metrics with name "' + match + '" not found to compute expression');
+          }
+        } else {
+          return match;
+        }
+      });
+
+      //check for correct math expression
+      if (!(validExpression && this.get('MATH_EXPRESSION_REGEX').test(beforeCompute))) {
+        validExpression = false;
+        console.error('Value for metric is not correct mathematical expression: ' + beforeCompute);
+      }
+
+      result['${' + _expression + '}'] = (validExpression) ? Number(window.eval(beforeCompute)).toString() : value;
+    }, this);
+    return result;
+  },
+
+  /*
+   * make call when clicking on "remove icon" on widget
+   */
+  hideWidget: function (event) {
+    this.get('controller').hideWidget(
+      {
+        context: Em.Object.create({
+          id: event.context
+        })
+      }
+    );
+  },
+
+  /*
+   * make call when clicking on "clone icon" on widget
+   */
+  cloneWidget: function (event) {
+    var self = this;
+    return App.showConfirmationPopup(
+      function() {
+        self.postWidgetDefinition();
+      },
+      Em.I18n.t('widget.clone.body').format(self.get('content.displayName')),
+      null,
+      null,
+      Em.I18n.t('common.clone')
+    );
+  },
+
+  /**
+   * collect all needed data to create new widget
+   * @returns {{WidgetInfo: {widget_name: *, display_name: *, widget_type: *, description: *, scope: *, metrics: *, values: *, properties: *}}}
+   */
+  collectWidgetData: function () {
+    return {
+      WidgetInfo: {
+        widget_name: this.get('content.widgetName'),
+        display_name: this.get('content.displayName'),
+        widget_type: this.get('content.widgetType'),
+        description: this.get('content.widgetDescription'),
+        scope: this.get('content.scope'),
+        "metrics": this.get('content.metrics').map(function (metric) {
+          return {
+            "name": metric.name,
+            "service_name": metric.serviceName,
+            "component_name": metric.componentName,
+            "metric_path": metric.metric_path,
+            "category": metric.category
+          }
+        }),
+        values: this.get('content.values'),
+        properties: this.get('content.properties')
+      }
+    };
+  },
+
+  /**
+   * post widget definition to server
+   * @returns {$.ajax}
+   */
+  postWidgetDefinition: function () {
+    return App.ajax.send({
+      name: 'widgets.wizard.add',
+      sender: this,
+      data: {
+        data: this.collectWidgetData()
+      },
+      success: 'postWidgetDefinitionSuccessCallback'
+    });
+  },
+
+  postWidgetDefinitionSuccessCallback: function() {
+
+  },
+
+  /*
+   * make call when clicking on "edit icon" on widget
+   */
+  editWidget: function (event) {
+    this.get('controller').editWidget(this.get('content'));
+  }
+
+});
+App.WidgetPreviewMixin = Ember.Mixin.create({
+  beforeRender: Em.K,
+  isLoaded: true,
+  metrics: [],
+  content: Em.Object.create({
+    widgetName: 'mock-widget',
+    values: []
+  }),
+  drawWidget: function () {
+    this.loadMetrics();
+    this.get('content').setProperties({
+      'values': this.get('controller.widgetValues'),
+      'properties': this.get('controller.widgetProperties'),
+      'displayName': this.get('controller.widgetName')
+    });
+    this._super();
+  }.observes('controller.widgetProperties', 'controller.widgetValues', 'controller.widgetMetrics', 'controller.widgetName'),
+  loadMetrics: function () {
+    var metrics = [];
+    this.get('controller.widgetMetrics').forEach(function (metric) {
+      metrics.push({
+        name: metric.name,
+        data: this.get('MOCK_VALUE')
+      });
+    }, this);
+    this.set('metrics', metrics);
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/mixins/common/widgets/widget_section.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widgets/widget_section.js b/ambari-web/app/mixins/common/widgets/widget_section.js
new file mode 100644
index 0000000..c8b76e9
--- /dev/null
+++ b/ambari-web/app/mixins/common/widgets/widget_section.js
@@ -0,0 +1,146 @@
+/**
+ * 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 App = require('app');
+
+App.WidgetSectionMixin = Ember.Mixin.create({
+  /**
+   * UI default layout name
+   */
+  defaultLayoutName: function () {
+    var heatmapType;
+    if (this.get('content.serviceName')) {
+      heatmapType = this.get('content.serviceName').toLowerCase();
+    } else {
+      heatmapType = "system";
+    }
+    return "default_" + heatmapType + this.layoutNameSuffix;
+  }.property('content.serviceName'),
+
+  /**
+   * UI section name
+   */
+  sectionName: function () {
+    if (this.get('content.serviceName')) {
+      return this.get('content.serviceName') + this.sectionNameSuffix;
+    } else {
+      return "SYSTEM"  + this.sectionNameSuffix
+    }
+  }.property('content.serviceName'),
+
+
+
+  /**
+   * Does Service has widget descriptor defined in the stack
+   * @type {boolean}
+   */
+  isServiceWithEnhancedWidgets: function () {
+    var isServiceWithWidgetdescriptor;
+    var serviceName = this.get('content.serviceName');
+    if (serviceName) {
+      isServiceWithWidgetdescriptor = App.StackService.find().findProperty('serviceName', serviceName).get('isServiceWithWidgets');
+    } else if (this.get('sectionName') === 'SYSTEM_HEATMAPS') {
+      isServiceWithWidgetdescriptor = true;
+    }
+    return isServiceWithWidgetdescriptor && App.supports.customizedWidgets;
+  }.property('content.serviceName'),
+
+  /**
+   *  @Type {App.WidgetLayout}
+   */
+  activeWidgetLayout: {},
+
+  /**
+   * @type {Em.A}
+   */
+  widgets: function () {
+    if (this.get('isWidgetsLoaded')) {
+      if (this.get('activeWidgetLayout.widgets')) {
+        return this.get('activeWidgetLayout.widgets').toArray();
+      } else {
+        return  [];
+      }
+    }
+  }.property('isWidgetsLoaded'),
+
+  /**
+   * load widgets defined by user
+   * @returns {$.ajax}
+   */
+  loadActiveWidgetLayout: function () {
+    this.set('activeWidgetLayout', {});
+    this.set('isWidgetsLoaded', false);
+    if (this.get('isServiceWithEnhancedWidgets')) {
+      return App.ajax.send({
+        name: 'widget.layout.get',
+        sender: this,
+        data: {
+          layoutName: this.get('defaultLayoutName'),
+          serviceName: this.get('content.serviceName')
+        },
+        success: 'loadActiveWidgetLayoutSuccessCallback'
+      });
+    } else {
+      this.set('isWidgetsLoaded', true);
+    }
+  },
+
+
+  /**
+   * success callback of <code>loadActiveWidgetLayout()</code>
+   * @param {object|null} data
+   */
+  loadActiveWidgetLayoutSuccessCallback: function (data) {
+    if (data.items[0]) {
+      App.widgetMapper.map(data.items[0].WidgetLayoutInfo);
+      App.widgetLayoutMapper.map(data);
+      this.set('activeWidgetLayout', App.WidgetLayout.find().findProperty('layoutName', this.get('defaultLayoutName')));
+      this.set('isWidgetsLoaded', true);
+    }
+  },
+
+  /**
+   * save layout after re-order widgets
+   * return {$.ajax}
+   */
+  saveWidgetLayout: function (widgets) {
+    var activeLayout = this.get('activeWidgetLayout');
+    var data = {
+      "WidgetLayoutInfo": {
+        "display_name": activeLayout.get("displayName"),
+        "id": activeLayout.get("id"),
+        "layout_name": activeLayout.get("layoutName"),
+        "scope": activeLayout.get("scope"),
+        "section_name": activeLayout.get("sectionName"),
+        "widgets": widgets.map(function (widget) {
+          return {
+            "id": widget.get('id')
+          }
+        })
+      }
+    };
+    return App.ajax.send({
+      name: 'widget.layout.edit',
+      sender: this,
+      data: {
+        layoutId: activeLayout.get("id"),
+        data: data
+      }
+    });
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/models/widget.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/widget.js b/ambari-web/app/models/widget.js
index 3ef265c..f0b604d 100644
--- a/ambari-web/app/models/widget.js
+++ b/ambari-web/app/models/widget.js
@@ -64,6 +64,8 @@ App.Widget = DS.Model.extend({
         return App.NumberWidgetView;
       case 'GAUGE':
         return App.GaugeWidgetView;
+      case 'HEATMAP':
+        return App.HeatmapWidgetView;
       default:
         return Em.View;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 81f5171..a311d49 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -142,8 +142,10 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
         route: '/heatmap',
         connectOutlets: function (router, context) {
           router.get('mainController').dataLoading().done(function () {
-            router.get('mainChartsHeatmapController').loadRacks();
-            router.get('mainChartsController').connectOutlet('mainChartsHeatmap');
+            router.get('mainChartsHeatmapController').loadRacks().done(function(data){
+              router.get('mainChartsHeatmapController').loadRacksSuccessCallback(data);
+              router.get('mainChartsController').connectOutlet('mainChartsHeatmap');
+            });
           });
         }
       }),
@@ -685,8 +687,10 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
           var item = router.get('mainServiceItemController.content');
           if (item.get('isLoaded')) {
             router.get('mainController').dataLoading().done(function () {
-              router.get('mainServiceInfoHeatmapController').loadRacks();
-              router.get('mainServiceItemController').connectOutlet('mainServiceInfoHeatmap', item);
+              router.get('mainServiceInfoHeatmapController').loadRacks().done(function(data) {
+                router.get('mainServiceInfoHeatmapController').loadRacksSuccessCallback(data);
+                router.get('mainServiceItemController').connectOutlet('mainServiceInfoHeatmap', item);
+              });
             });
           }
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/templates/common/widget/heatmap_widget.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/widget/heatmap_widget.hbs b/ambari-web/app/templates/common/widget/heatmap_widget.hbs
new file mode 100644
index 0000000..215fb1c
--- /dev/null
+++ b/ambari-web/app/templates/common/widget/heatmap_widget.hbs
@@ -0,0 +1,39 @@
+{{!
+* 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.
+}}
+
+<div class="heatmap-widget">
+  <div class="span10 heatmap-content">
+    <h4 id="heatmap-metric-loading">
+	        <span id="heatmap-metric-title">
+						{{view.content.displayName}} &nbsp;
+            {{#unless view.isLoaded}}
+              <i class='icon-spinner icon-spin icon-small'></i>
+            {{/unless}}
+					</span>
+    </h4>
+
+    <div class="row-fluid">
+      {{#each rack in view.racks}}
+        <div {{bindAttr class="controller.rackClass"}}>
+          {{view App.MainChartsHeatmapRackView rackBinding="rack" }}
+        </div>
+      {{/each}}
+    </div>
+    {{view App.MainChartsHeatmapHostDetailView}}
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/templates/main/charts/heatmap.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/charts/heatmap.hbs b/ambari-web/app/templates/main/charts/heatmap.hbs
index 89a9a37..05b8da0 100644
--- a/ambari-web/app/templates/main/charts/heatmap.hbs
+++ b/ambari-web/app/templates/main/charts/heatmap.hbs
@@ -19,59 +19,35 @@
 <div class="heatmap">
 
   <div class="container-fluid">
-	  <div class="row-fluid">
-	    <div class="span2 legend-column">
-		     <div class="btn-group" id="select-metric-btn-group">
-				  <button class="btn heatmap-select-metric-btn">{{t charts.heatmap.selectMetric}}</button>
-				  <button class="btn dropdown-toggle heatmap-toggle-metrics-btn" data-toggle="dropdown">
-				    <span class="caret"></span>
-				  </button>
-				  <ul class="dropdown-menu">
-				    {{#each metric in controller.allMetrics}}
-							<li class="heatmap-metrics-dropdown-links">
-                <a tabindex="-1" {{action showHeatMapMetric metric target="controller"}}>{{metric.name}}</a>
-							</li>
-            {{/each}}
-				  </ul>
-				</div>
+    <div class="row-fluid">
+      <div class="span2 legend-column">
+
+        {{view view.dropdownView}}
+
         {{#if controller.selectedMetric}}
-					<table class="legend">
-					  {{#each slot in controller.selectedMetric.slotDefinitions}}
-					    <tr>
-					      <td>
-					        <div class="tile" {{bindAttr style="slot.cssStyle"}}></div>
-					      </td>
-					      <td>{{slot.label}}</td>
-					    </tr>
-					  {{/each}}
-					</table>
-	        {{t common.maximum}}:
-	        <div id="inputMaximum" class="control-group">
-	          {{view Ember.TextField type="text" maxlength="8" valueBinding="controller.inputMaximum" class="span6"}}
-	          {{controller.selectedMetric.units}}
-	        </div>
+          <table class="legend">
+            {{#each slot in controller.selectedMetric.slotDefinitions}}
+              <tr>
+                <td>
+                  <div class="tile" {{bindAttr style="slot.cssStyle"}}></div>
+                </td>
+                <td>{{slot.label}}</td>
+              </tr>
+            {{/each}}
+          </table>
+          {{t common.maximum}}:
+          <div id="inputMaximum" class="control-group">
+            {{view Ember.TextField type="text" maxlength="8" valueBinding="controller.inputMaximum" class="span6"}}
+            {{controller.selectedMetric.units}}
+          </div>
         {{/if}}
-	    </div>
-	    <div class="span10 heatmap-content">
-	      <h4 id="heatmap-metric-loading">
-	        <span id="heatmap-metric-title">
-						{{controller.selectedMetric.name}} &nbsp;
-						{{#if controller.selectedMetric.loading}}
-              <i class='icon-spinner icon-spin icon-small'></i>
-						{{/if}}
-					</span>
-	      </h4>
-	      <div class="row-fluid">
-
-				  {{#each rack in controller.racks}}
-				    <div {{bindAttr class="controller.rackClass"}}>
-				      {{view App.MainChartsHeatmapRackView rackBinding="rack" }}
-				    </div>
-				  {{/each}}
-			  </div>
-			  {{view App.MainChartsHeatmapHostDetailView}}
-	    </div>
-	  </div>
+      </div>
+      {{#if controller.activeWidget}}
+        <div class="active-widget" {{bindAttr id="activeWidget.id"}}>
+          {{view activeWidget.viewClass contentBinding="activeWidget" racksBinding = "racks" idBinding="activeWidget.id"}}
+        </div>
+      {{/if}}
+    </div>
   </div>
 
 </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/templates/main/charts/heatmap_dropdown.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/charts/heatmap_dropdown.hbs b/ambari-web/app/templates/main/charts/heatmap_dropdown.hbs
new file mode 100644
index 0000000..8904d49
--- /dev/null
+++ b/ambari-web/app/templates/main/charts/heatmap_dropdown.hbs
@@ -0,0 +1,38 @@
+{{!
+* 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.
+}}
+
+<div class="btn-group">
+  <button class="btn heatmap-select-metric-btn">{{t charts.heatmap.selectMetric}}</button>
+  <button class="btn dropdown-toggle heatmap-toggle-metrics-btn" data-toggle="dropdown">
+    <span class="caret"></span>
+  </button>
+  <ul class="dropdown-menu">
+    {{#each category in controller.heatmapCategories}}
+      <li class="dropdown-submenu">
+        <a tabindex="-1" >{{category.displayName}}</a>
+        <ul class="dropdown-menu">
+          {{#each heatmap in category.heatmaps}}
+            <li>
+              <a tabindex="-1" {{action showHeatMapMetric heatmap target="controller"}}>{{heatmap.display_name}}</a>
+            </li>
+          {{/each}}
+        </ul>
+      </li>
+    {{/each}}
+  </ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/templates/main/service/info/heatmap_dropdown.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/info/heatmap_dropdown.hbs b/ambari-web/app/templates/main/service/info/heatmap_dropdown.hbs
new file mode 100644
index 0000000..8986c45
--- /dev/null
+++ b/ambari-web/app/templates/main/service/info/heatmap_dropdown.hbs
@@ -0,0 +1,32 @@
+{{!
+* 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.
+}}
+
+<div class="btn-group" id="select-metric-btn-group">
+  <button class="btn heatmap-select-metric-btn">{{t charts.heatmap.selectMetric}}</button>
+  <button class="btn dropdown-toggle heatmap-toggle-metrics-btn" data-toggle="dropdown">
+    <span class="caret"></span>
+  </button>
+
+  <ul class="dropdown-menu">
+    {{#each heatmap in controller.allHeatmaps}}
+      <li class="heatmap-metrics-dropdown-links">
+        <a tabindex="-1" {{action showHeatMapMetric heatmap target="controller"}}>{{heatmap.display_name}}</a>
+      </li>
+    {{/each}}
+  </ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 366cf5d..5328272 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -2406,6 +2406,11 @@ var urls = {
     }
   },
 
+  'widgets.get': {
+    real: '/clusters/{clusterName}/widgets?{urlParams}',
+    mock: '/data/widget_layouts/all_heatmaps.json'
+  },
+
   'widgets.all.shared.get': {
     real: '/clusters/{clusterName}/widgets?WidgetInfo/scope=CLUSTER&fields=*',
     mock: '/data/widget_layouts/all_shared_widgets.json'
@@ -2472,6 +2477,11 @@ var urls = {
     mock: '/data/metrics/{serviceName}/Append_num_ops.json'
   },
 
+  'widgets.hosts.metrics.get': {
+    real: '/clusters/{clusterName}/hosts?fields={metricPaths}',
+    mock: '/data/metrics/{serviceName}/Append_num_ops.json'
+  },
+
   'widgets.wizard.metrics.get': {
     real: '{stackVersionURL}/services?artifacts/Artifacts/artifact_name=metrics_descriptor&StackServices/service_name.in({serviceNames})&fields=artifacts/*',
     mock: '/data/metrics/HBASE/definition.json'

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/utils/heatmap.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/heatmap.js b/ambari-web/app/utils/heatmap.js
index d8672b1..9d8c178 100644
--- a/ambari-web/app/utils/heatmap.js
+++ b/ambari-web/app/utils/heatmap.js
@@ -39,7 +39,7 @@ module.exports = {
               value = transformValueFunction(value);
             }
             var hostName = hc.HostRoles.host_name;
-            hostToValueMap[hostName] = value;
+            hostToValueMap[hostName] = value.toFixed(1);
           }
         });
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index b0e1cac..b39eb2f 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -76,6 +76,7 @@ require('views/common/widget/graph_widget_view');
 require('views/common/widget/template_widget_view');
 require('views/common/widget/gauge_widget_view');
 require('views/common/widget/number_widget_view');
+require('views/common/widget/heatmap_widget_view');
 require('views/common/assign_master_components_view');
 require('views/login');
 require('views/main');

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/common/widget/heatmap_widget_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/widget/heatmap_widget_view.js b/ambari-web/app/views/common/widget/heatmap_widget_view.js
new file mode 100644
index 0000000..4153f30
--- /dev/null
+++ b/ambari-web/app/views/common/widget/heatmap_widget_view.js
@@ -0,0 +1,116 @@
+/**
+ * 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 App = require('app');
+
+App.HeatmapWidgetView = Em.View.extend(App.WidgetMixin, {
+  templateName: require('templates/common/widget/heatmap_widget'),
+
+  /**
+   * common metrics container
+   * @type {Array}
+   */
+  metrics: [],
+
+  /**
+   *  racks container  binded in the template
+   *  @type {Array}
+   */
+  racks: [],
+
+  /**
+   * draw widget
+   */
+  drawWidget: function () {
+    if (this.get('isLoaded')) {
+      var hostToValueMap = this.calculateValues();
+      var hostNames = [];
+      if (this.get('racks').everyProperty('isLoaded', true)) {
+        this.get('racks').forEach(function (rack) {
+          hostNames = hostNames.concat(rack.hosts.mapProperty('hostName'));
+        });
+      }
+
+      var metricObject = App.MainChartHeatmapMetric.create({
+        name: this.get('content.displayName'),
+        units: this.get('content.properties.display_unit'),
+        maximumValue: this.get('content.properties.max_limit'),
+        hostNames: hostNames,
+        hostToValueMap: hostToValueMap
+      });
+
+      this.set('controller.selectedMetric', metricObject);
+
+      this.set('controller.inputMaximum', metricObject.get('maximumValue'));
+    }
+  },
+
+  /**
+   * calculate value for heatmap widgets
+   */
+  calculateValues: function () {
+    var metrics = this.get('metrics');
+    var hostToValueMap = this.computeExpression(this.extractExpressions(this.get('content.values')[0]), metrics);
+    return hostToValueMap;
+  },
+
+
+  /**
+   * compute expression
+   * @param expressions
+   * @param metrics
+   * @returns {object}
+   */
+  computeExpression: function (expressions, metrics) {
+    var hostToValueMap = {};
+    var hostNames = metrics.mapProperty('hostName');
+    hostNames.forEach(function (_hostName) {
+      expressions.forEach(function (_expression) {
+        var validExpression = true;
+
+        //replace values with metrics data
+        var beforeCompute = _expression.replace(this.get('VALUE_NAME_REGEX'), function (match) {
+          var _metric;
+          if (window.isNaN(match)) {
+            _metric = metrics.filterProperty('name', match).findProperty('hostName', _hostName);
+            if (_metric) {
+              return _metric.data;
+            } else {
+              validExpression = false;
+              console.error('Metrics with name "' + match + '" not found to compute expression');
+            }
+          } else {
+            return match;
+          }
+        });
+
+        if (validExpression && this.get('MATH_EXPRESSION_REGEX').test(beforeCompute)) {
+          var value = Number(window.eval(beforeCompute)).toString();
+          if (value == "NaN")  {
+            value = 0
+          }
+          hostToValueMap[_hostName] = value;
+        } else {
+          console.error('Value for metric is not correct mathematical expression: ' + beforeCompute);
+        }
+      }, this);
+    }, this);
+
+    return hostToValueMap;
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/main/charts/heatmap.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/charts/heatmap.js b/ambari-web/app/views/main/charts/heatmap.js
index 5147123..431a7e2 100644
--- a/ambari-web/app/views/main/charts/heatmap.js
+++ b/ambari-web/app/views/main/charts/heatmap.js
@@ -22,7 +22,10 @@ App.MainChartsHeatmapView = Em.View.extend({
   didInsertElement: function () {
     this._super();
     // set default metric
-    this.set('controller.selectedMetric', this.get('controller.allMetrics')[0]);
+    this.get('controller').loadPageData();
     $("#heatmapDetailsBlock").hide();
-  }
+  },
+  dropdownView: Em.View.extend({
+    templateName: require('templates/main/charts/heatmap_dropdown')
+  })
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/main/charts/heatmap/heatmap_host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/charts/heatmap/heatmap_host.js b/ambari-web/app/views/main/charts/heatmap/heatmap_host.js
index 6f54221..d42255e 100644
--- a/ambari-web/app/views/main/charts/heatmap/heatmap_host.js
+++ b/ambari-web/app/views/main/charts/heatmap/heatmap_host.js
@@ -21,6 +21,11 @@ var App = require('app');
 
 App.MainChartsHeatmapHostView = Em.View.extend({
   templateName: require('templates/main/charts/heatmap/heatmap_host'),
+
+  didInsertElement: function() {
+    $("#heatmapDetailsBlock").hide();
+  },
+
   /** @private */
   hostClass: 'hostBlock',
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/main/charts/heatmap/heatmap_rack.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/charts/heatmap/heatmap_rack.js b/ambari-web/app/views/main/charts/heatmap/heatmap_rack.js
index 35653cd..aa7c95c 100644
--- a/ambari-web/app/views/main/charts/heatmap/heatmap_rack.js
+++ b/ambari-web/app/views/main/charts/heatmap/heatmap_rack.js
@@ -29,31 +29,12 @@ App.MainChartsHeatmapRackView = Em.View.extend({
   /** loaded hosts of rack */
   hosts: [],
 
-  willDestroyElement: function () {
-    this.get('hosts').clear();
-  },
-
-  /**
-   * get hosts from the root controller
-   */
-  getHosts: function () {
-    var controller = this.get('controller');
-    var rackId = this.get('rack.rackId');
-    var rackMap = controller.get('rackMap');
-    this.pushHostsToRack(rackMap[rackId].hosts);
-  },
-
-  getHostsSuccessCallback: function (data, opt, params) {
-    this.pushHostsToRack(data);
-    this.displayHosts();
-  },
-
   /**
    * display hosts of rack
    */
   displayHosts: function () {
     var rackHosts = this.get('rack.hosts');
-    var rackCount = this.get('controller.modelRacks.length');
+    var rackCount = this.get('controller.racks.length');
 
     if (this.get('hosts.length') === 0) {
       if (rackHosts.length > 100 && rackCount == 1) {
@@ -72,77 +53,7 @@ App.MainChartsHeatmapRackView = Em.View.extend({
     }
   },
 
-  getHostsErrorCallback: function (request, ajaxOptions, error, opt, params) {
-    this.set('rack.isLoaded', true);
-  },
-  /**
-   * push hosts to rack
-   * @param data
-   */
-  pushHostsToRack: function (hosts) {
-    var newHostsData = hosts;
-    var rackHosts = this.get('rack.hosts');
-
-    if (rackHosts.length > 0) {
-      this.updateLoadedHosts(rackHosts, newHostsData);
-    } else {
-      this.set('rack.hosts', newHostsData);
-    }
-  },
-
-  updateLoadedHosts: function (rackHosts, newHostsData) {
-    var rackHostsMap = {};
-    var isNewHosts = false;
-
-    //create map
-    rackHosts.forEach(function (host) {
-      rackHostsMap[host.hostName] = host;
-    });
-
-    newHostsData.forEach(function (item) {
-      var currentHostInfo = rackHostsMap[item.hostName];
-
-      if (currentHostInfo) {
-        ['diskTotal', 'diskFree', 'cpuSystem', 'cpuUser', 'memTotal', 'memFree', 'hostComponents'].forEach(function (property) {
-          currentHostInfo[property] = item[property];
-        });
-        delete rackHostsMap[item.hostName];
-      } else {
-        isNewHosts = true;
-      }
-    }, this);
-
-    //if hosts were deleted or added then reload hosts view
-    if (!App.isEmptyObject(rackHostsMap) || isNewHosts) {
-      this.redrawHostsView(newHostsData)
-    }
-  },
-
-  /**
-   * reload hosts rack
-   * @param newHostsData
-   */
-  redrawHostsView: function (newHostsData) {
-    this.set('rack.isLoaded', false);
-    this.get('hosts').clear();
-    this.set('rack.hosts', newHostsData);
-  },
-
-  /**
-   * call metrics update after hosts of rack are loaded
-   */
-  updateMetrics: function(){
-    if (this.get('rack.isLoaded')) {
-      this.get('controller').loadMetrics();
-    }
-  }.observes('rack.isLoaded'),
-
   didInsertElement: function () {
-    this.set('rack.isLoaded', false);
-    if (this.get('rack.hosts.length') > 0) {
-      this.displayHosts();
-    }
-    this.getHosts();
     this.get('controller').addRackView(this);
   },
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/main/service/info/heatmap_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/heatmap_view.js b/ambari-web/app/views/main/service/info/heatmap_view.js
index fb6a2d1..580adb7 100644
--- a/ambari-web/app/views/main/service/info/heatmap_view.js
+++ b/ambari-web/app/views/main/service/info/heatmap_view.js
@@ -17,5 +17,7 @@
  */
 var App = require('app');
 App.MainServiceInfoHeatmapView = App.MainChartsHeatmapView.extend({
-  templateName: require('templates/main/charts/heatmap')
+  dropdownView: Em.View.extend({
+    templateName: require('templates/main/service/info/heatmap_dropdown')
+  })
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index 60734f1..22af416 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -598,7 +598,7 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, {
           var widgets = misc.sortByOrder($("#widget_layout .widget").map(function () {
             return this.id;
           }), self.get('controller.widgets'));
-          self.get('controller').saveReorderedLayout(widgets);
+          self.get('controller').saveWidgetLayout(widgets);
         },
         activate: function (event, ui) {
           self.set('isMoving', true);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO_test.js
deleted file mode 100644
index 6f46539..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO_test.js
+++ /dev/null
@@ -1,113 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO');
-
-describe('App.MainChartHeatmapCpuWaitIOMetric', function () {
-
-  var tests = [
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "cpu" : {
-                "cpu_wio" : 0.4
-              }
-            }
-          }
-        ]
-      },
-      m: 'One host',
-      e: {'dev01.hortonworks.com': '40.0'}
-    },
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "cpu" : {
-                "cpu_wio" : 0.4
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "cpu" : {
-                "cpu_wio" : 0.34566
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts',
-      e: {'dev01.hortonworks.com': '40.0', 'dev02.hortonworks.com': '34.6'}
-    },
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "cpu" : {
-                "cpu_wio" : 0.4
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "cpu" : {
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts, One without metric',
-      e: {'dev01.hortonworks.com': '40.0'}
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapCpuWaitIOMetric = App.MainChartHeatmapCpuWaitIOMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapCpuWaitIOMetric.metricMapper(test.json);
-        expect(r).to.eql(test.e);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread_test.js
deleted file mode 100644
index cebf41d..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread_test.js
+++ /dev/null
@@ -1,45 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread');
-
-describe('App.MainChartHeatmapDFSBytesReadMetric', function () {
-
-  var tests = [
-    {i: 0, e: 0},
-    {i: 0.5 * 1024* 1024, e: 0.5},
-    {i: 1024* 1024, e: 1},
-    {i: 10.5 * 1024 * 1024,e: 10.5}
-  ];
-
-  describe('#transformValue()', function() {
-    var mainChartHeatmapDFSBytesReadMetric = App.MainChartHeatmapDFSBytesReadMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.i + ' bytes to ' + test.e + ' MB', function() {
-        var r = mainChartHeatmapDFSBytesReadMetric.transformValue(test.i);
-        expect(r).to.eql(test.e);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten_test.js
deleted file mode 100644
index 240802e..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten_test.js
+++ /dev/null
@@ -1,45 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten');
-
-describe('App.MainChartHeatmapDFSBytesWrittenMetric', function () {
-
-  var tests = [
-    {i: 0, e: 0},
-    {i: 0.5 * 1024* 1024, e: 0.5},
-    {i: 1024* 1024, e: 1},
-    {i: 10.5 * 1024 * 1024,e: 10.5}
-  ];
-
-  describe('#transformValue()', function() {
-    var mainChartHeatmapDFSBytesWrittenMetric = App.MainChartHeatmapDFSBytesWrittenMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.i + ' bytes to ' + test.e + ' MB', function() {
-        var r = mainChartHeatmapDFSBytesWrittenMetric.transformValue(test.i);
-        expect(r).to.eql(test.e);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_test.js
deleted file mode 100644
index 06d62c2..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_test.js
+++ /dev/null
@@ -1,115 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs');
-
-describe('App.MainChartHeatmapDFSMetrics', function () {
-
-  var tests = [
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "gcTimeMillis" : 285
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 285},
-      m: 'One host_component'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "gcTimeMillis" : 285
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "gcTimeMillis" : 124
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 285, 'dev02.hortonworks.com': 124},
-      m: 'Two host_components'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-                "gcTimeMillis" : 285
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "jvm" : {
-
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 285},
-      m: 'Two host_components, one without metric'
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapDFSMetrics = App.MainChartHeatmapDFSMetrics.create();
-    mainChartHeatmapDFSMetrics.set('defaultMetric', 'metrics.jvm.gcTimeMillis');
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapDFSMetrics.metricMapper(test.json);
-        expect(r).to.eql(test.result);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused_test.js
deleted file mode 100644
index 312c9c6..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused_test.js
+++ /dev/null
@@ -1,116 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused');
-
-describe('App.MainChartHeatmapDiskSpaceUsedMetric', function () {
-
-  var tests = Em.A([
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "disk" : {
-                "disk_free" : 89.973,
-                "disk_total" : 101.515
-              }
-            }
-          }
-        ]
-      },
-      m: 'One host',
-      e: {'dev01.hortonworks.com': 11.37}
-    },
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "disk" : {
-                "disk_free" : 89.973,
-                "disk_total" : 101.515
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "disk" : {
-                "disk_free" : 89.973,
-                "disk_total" : 101.515
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts',
-      e: {'dev01.hortonworks.com': 11.37, 'dev02.hortonworks.com': 11.37}
-    },
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "disk" : {
-                "disk_free" : 89.973,
-                "disk_total" : 101.515
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-
-            }
-          }
-        ]
-      },
-      m: 'Two hosts, One without metric',
-      e: {'dev01.hortonworks.com': 11.37}
-    }
-  ]);
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapDiskSpaceUsedMetric = App.MainChartHeatmapDiskSpaceUsedMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapDiskSpaceUsedMetric.metricMapper(test.json);
-        expect(r).to.eql(test.e);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_test.js
deleted file mode 100644
index a1f0325..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_test.js
+++ /dev/null
@@ -1,125 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase');
-
-describe('App.MainChartHeatmapHbaseMetrics', function () {
-
-  var tests = [
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "hbase" : {
-                "regionserver" : {
-                  "readRequestsCount" : 0.0
-                }
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 0},
-      m: 'One host_component'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "hbase" : {
-                "regionserver" : {
-                  "readRequestsCount" : 0.0
-                }
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "hbase" : {
-                "regionserver" : {
-                  "readRequestsCount" : 1.0
-                }
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 0, 'dev02.hortonworks.com': 1},
-      m: 'Two host_components'
-    },
-    {
-      json: {
-        "host_components" : [
-          {
-            "HostRoles" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "hbase" : {
-                "regionserver" : {
-                  "readRequestsCount" : 0.0
-                }
-              }
-            }
-          },
-          {
-            "HostRoles" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "hbase" : {
-                "regionserver" : {
-
-                }
-              }
-            }
-          }
-        ]
-      },
-      result: {'dev01.hortonworks.com': 0},
-      m: 'Two host_components, one without metric'
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapHbaseMetrics = App.MainChartHeatmapHbaseMetrics.create();
-    mainChartHeatmapHbaseMetrics.set('defaultMetric', 'metrics.hbase.regionserver.readRequestsCount');
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapHbaseMetrics.metricMapper(test.json);
-        expect(r).to.eql(test.result);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused_test.js
deleted file mode 100644
index 8886d8a..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused_test.js
+++ /dev/null
@@ -1,136 +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.
- */
-
-var App = require('app');
-require('messages');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused');
-
-describe('App.MainChartHeatmapMemoryUsedMetric', function () {
-
-  var tests = [
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "memory" : {
-                "mem_buffers" : 109888.0,
-                "mem_cached" : 1965624.0,
-                "mem_free" : 261632.0,
-                "mem_shared" : 0.0,
-                "mem_total" : 6123776.0,
-                "swap_free" : 4126820.0,
-                "swap_total" : 4128760.0
-              }
-            }
-          }
-        ]
-      },
-      m: 'One host',
-      e: {'dev01.hortonworks.com': '63.6'}
-    },
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "memory" : {
-                "mem_buffers" : 109888.0,
-                "mem_cached" : 1965624.0,
-                "mem_free" : 261632.0,
-                "mem_shared" : 0.0,
-                "mem_total" : 6123776.0,
-                "swap_free" : 4126820.0,
-                "swap_total" : 4128760.0
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "memory" : {
-                "mem_buffers" : 109888.0,
-                "mem_cached" : 1965624.0,
-                "mem_free" : 261632.0,
-                "mem_shared" : 0.0,
-                "mem_total" : 6123776.0,
-                "swap_free" : 4126820.0,
-                "swap_total" : 4128760.0
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts',
-      e: {'dev01.hortonworks.com': '63.6', 'dev02.hortonworks.com': '63.6'}
-    },
-    {
-      json:{
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "memory" : {
-                "mem_buffers" : 109888.0,
-                "mem_cached" : 1965624.0,
-                "mem_free" : 261632.0,
-                "mem_shared" : 0.0,
-                "mem_total" : 6123776.0,
-                "swap_free" : 4126820.0,
-                "swap_total" : 4128760.0
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-
-            }
-          }
-        ]
-      },
-      m: 'Two hosts, One without metric',
-      e: {'dev01.hortonworks.com': '63.6'}
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapMemoryUsedMetric = App.MainChartHeatmapMemoryUsedMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapMemoryUsedMetric.metricMapper(test.json);
-        expect(r).to.eql(test.e);
-      });
-    });
-
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun_test.js
deleted file mode 100644
index f23d02c..0000000
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun_test.js
+++ /dev/null
@@ -1,111 +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.
- */
-
-var App = require('app');
-
-require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_processrun');
-
-describe('App.MainChartHeatmapProcessRunMetric', function () {
-
-  var tests = [
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "process" : {
-                "proc_run" : 0.0
-              }
-            }
-          }
-        ]
-      },
-      m: 'One host',
-      result: {'dev01.hortonworks.com': '0.0'}
-    },
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "process" : {
-                "proc_run" : 0.1
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "process" : {
-                "proc_run" : 0.46
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts',
-      result: {'dev01.hortonworks.com': '0.1', 'dev02.hortonworks.com': '0.5'}
-    },
-    {
-      json: {
-        "items" : [
-          {
-            "Hosts" : {
-              "host_name" : "dev01.hortonworks.com"
-            },
-            "metrics" : {
-              "process" : {
-                "proc_run" : 0.99
-              }
-            }
-          },
-          {
-            "Hosts" : {
-              "host_name" : "dev02.hortonworks.com"
-            },
-            "metrics" : {
-              "process" : {
-              }
-            }
-          }
-        ]
-      },
-      m: 'Two hosts, One without metric',
-      result: {'dev01.hortonworks.com': '1.0'}
-    }
-  ];
-
-  describe('#metricMapper()', function() {
-    var mainChartHeatmapProcessRunMetric = App.MainChartHeatmapProcessRunMetric.create();
-
-    tests.forEach(function(test) {
-      it(test.m, function() {
-        var r = mainChartHeatmapProcessRunMetric.metricMapper(test.json);
-        expect(r).to.eql(test.result);
-      });
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_test.js b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_test.js
index fb134e4..77fef25 100644
--- a/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_test.js
+++ b/ambari-web/test/controllers/main/charts/heatmap_metrics/heatmap_metric_test.js
@@ -43,30 +43,6 @@ describe('MainChartHeatmapMetric', function () {
     });
   });
 
-  describe('#refreshHostSlots', function() {
-    beforeEach(function() {
-      sinon.stub(App.ajax, 'send', Em.K);
-    });
-
-    afterEach(function() {
-      App.ajax.send.restore();
-    });
-
-    it('Should load proper URL', function() {
-      mainChartHeatmapMetric.set('ajaxData', {
-        serviceName: 'SERVICE',
-        componentName: 'COMPONENT'
-      });
-      mainChartHeatmapMetric.set('defaultMetric', 'default.metric');
-      mainChartHeatmapMetric.refreshHostSlots();
-      expect(App.ajax.send.getCall(0).args[0].data).to.eql({
-        "metricName": "default/metric",
-        "serviceName": "SERVICE",
-        "componentName": "COMPONENT"
-      });
-      expect(App.ajax.send.getCall(0).args[0].name).to.equal('hosts.metrics');
-    });
-  });
 
   describe('#slotDefinitions', function () {
     beforeEach(function () {
@@ -304,23 +280,4 @@ describe('MainChartHeatmapMetric', function () {
     });
   });
 
-  describe('#refreshHostSlotsSuccessCallback()', function () {
-    it('launch metricMapper with recieved data', function () {
-      sinon.stub(mainChartHeatmapMetric, 'metricMapper').returns({'host1': 1});
-      mainChartHeatmapMetric.refreshHostSlotsSuccessCallback({data: 'data'});
-      expect(mainChartHeatmapMetric.get('hostToValueMap')).to.eql({'host1': 1});
-      expect(mainChartHeatmapMetric.get('loading')).to.be.false;
-      expect(mainChartHeatmapMetric.metricMapper.calledWith({data: 'data'})).to.be.true;
-      mainChartHeatmapMetric.metricMapper.restore();
-    });
-  });
-
-  describe('#refreshHostSlotsErrorCallback()', function () {
-    it('', function () {
-      mainChartHeatmapMetric.set('loading', undefined);
-      mainChartHeatmapMetric.refreshHostSlotsErrorCallback({data: 'data'});
-      expect(mainChartHeatmapMetric.get('loading')).to.be.false;
-    });
-  });
-
 });


[3/3] ambari git commit: AMBARI-10648. Integrate Heatmap pages with widget and widget layout API. (jaimin)

Posted by ja...@apache.org.
AMBARI-10648. Integrate Heatmap pages with widget and widget layout API. (jaimin)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/9639005f
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/9639005f
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/9639005f

Branch: refs/heads/trunk
Commit: 9639005f6464117195632d57d4cfbcb9e12e7ed1
Parents: a93a312
Author: Jaimin Jetly <ja...@hortonworks.com>
Authored: Wed Apr 22 13:48:11 2015 -0700
Committer: Jaimin Jetly <ja...@hortonworks.com>
Committed: Wed Apr 22 13:48:18 2015 -0700

----------------------------------------------------------------------
 .../HBASE/0.96.0.2.0/widgets.json               |  12 +-
 .../common-services/HDFS/2.1.0.2.0/widgets.json |   4 +-
 .../common-services/YARN/2.1.0.2.0/widgets.json |   4 +-
 .../resources/stacks/HDP/2.0.6/widgets.json     |   2 +-
 .../stacks/HDP/2.3/services/HBASE/widgets.json  |  12 +-
 .../widget_layouts/HBASE/default_dashboard.json |   4 +-
 .../data/widget_layouts/all_heatmaps.json       | 258 ++++++++++
 ambari-web/app/assets/test/tests.js             |  10 -
 ambari-web/app/controllers.js                   |  19 -
 .../app/controllers/main/charts/heatmap.js      | 187 +++++--
 .../charts/heatmap_metrics/heatmap_metric.js    |  88 +---
 .../heatmap_metrics/heatmap_metric_cpuWaitIO.js |  39 --
 .../heatmap_metrics/heatmap_metric_dfs.js       |  45 --
 .../heatmap_metric_dfs_bytesread.js             |  32 --
 .../heatmap_metric_dfs_byteswritten.js          |  32 --
 .../heatmap_metric_dfs_gctime.js                |  29 --
 .../heatmap_metric_dfs_memHeapUsed.js           |  29 --
 .../heatmap_metric_diskspaceused.js             |  65 ---
 .../heatmap_metrics/heatmap_metric_hbase.js     |  46 --
 .../heatmap_metric_hbase_compactionqueue.js     |  29 --
 .../heatmap_metric_hbase_memstoresize.js        |  29 --
 .../heatmap_metric_hbase_readrequest.js         |  29 --
 .../heatmap_metric_hbase_regions.js             |  29 --
 .../heatmap_metric_hbase_writerequest.js        |  29 --
 .../heatmap_metric_memoryused.js                |  63 ---
 .../heatmap_metric_processrun.js                |  45 --
 .../heatmap_metrics/heatmap_metric_yarn.js      |  46 --
 .../heatmap_metric_yarn_ResourceUsed.js         |  66 ---
 .../heatmap_metric_yarn_gctime.js               |  29 --
 .../heatmap_metric_yarn_memHeapUsed.js          |  29 --
 .../controllers/main/service/info/heatmap.js    |  33 +-
 .../controllers/main/service/info/summary.js    | 115 +----
 ambari-web/app/messages.js                      |  17 -
 ambari-web/app/mixins.js                        |   3 +-
 ambari-web/app/mixins/common/widget_mixin.js    | 426 ----------------
 .../app/mixins/common/widgets/widget_mixin.js   | 506 +++++++++++++++++++
 .../app/mixins/common/widgets/widget_section.js | 146 ++++++
 ambari-web/app/models/widget.js                 |   2 +
 ambari-web/app/routes/main.js                   |  12 +-
 .../templates/common/widget/heatmap_widget.hbs  |  39 ++
 .../app/templates/main/charts/heatmap.hbs       |  78 +--
 .../templates/main/charts/heatmap_dropdown.hbs  |  38 ++
 .../main/service/info/heatmap_dropdown.hbs      |  32 ++
 ambari-web/app/utils/ajax/ajax.js               |  10 +
 ambari-web/app/utils/heatmap.js                 |   2 +-
 ambari-web/app/views.js                         |   1 +
 .../views/common/widget/heatmap_widget_view.js  | 116 +++++
 ambari-web/app/views/main/charts/heatmap.js     |   7 +-
 .../views/main/charts/heatmap/heatmap_host.js   |   5 +
 .../views/main/charts/heatmap/heatmap_rack.js   |  91 +---
 .../app/views/main/service/info/heatmap_view.js |   4 +-
 .../app/views/main/service/info/summary.js      |   2 +-
 .../heatmap_metric_cpuWaitIO_test.js            | 113 -----
 .../heatmap_metric_dfs_bytesread_test.js        |  45 --
 .../heatmap_metric_dfs_byteswritten_test.js     |  45 --
 .../heatmap_metrics/heatmap_metric_dfs_test.js  | 115 -----
 .../heatmap_metric_diskspaceused_test.js        | 116 -----
 .../heatmap_metric_hbase_test.js                | 125 -----
 .../heatmap_metric_memoryused_test.js           | 136 -----
 .../heatmap_metric_processrun_test.js           | 111 ----
 .../heatmap_metrics/heatmap_metric_test.js      |  43 --
 .../heatmap_metric_yarn_ResourceUsed_test.js    | 128 -----
 .../heatmap_metrics/heatmap_metric_yarn_test.js | 115 -----
 .../controllers/main/charts/heatmap_test.js     |  52 +-
 64 files changed, 1384 insertions(+), 2785 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/widgets.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/widgets.json b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/widgets.json
index 8920843..b79c281 100644
--- a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/widgets.json
+++ b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/widgets.json
@@ -139,7 +139,7 @@
           "is_visible": true,
           "metrics": [
             {
-              "name": "ipc.IPC.numOpenConnections",
+              "name": "regionserver.RegionServer.numOpenConnections",
               "metric_path": "metrics/hbase/ipc/IPC/numOpenConnections",
               "category": "",
               "service_name": "HBASE",
@@ -149,7 +149,7 @@
           "values": [
             {
               "name": "Open Connections",
-              "value": "${ipc.IPC.numOpenConnections}"
+              "value": "${regionserver.RegionServer.numOpenConnections}"
             }
           ],
           "properties": {
@@ -165,13 +165,13 @@
           "is_visible": true,
           "metrics": [
             {
-              "name": "ipc.IPC.numActiveHandler",
+              "name": "regionserver.RegionServer.numActiveHandler",
               "metric_path": "metrics/hbase/ipc/IPC/numActiveHandler",
               "service_name": "HBASE",
               "component_name": "HBASE_REGIONSERVER"
             },
             {
-              "name": "ipc.IPC.numCallsInGeneralQueue",
+              "name": "regionserver.RegionServer.numCallsInGeneralQueue",
               "metric_path": "metrics/hbase/ipc/IPC/numCallsInGeneralQueue",
               "service_name": "HBASE",
               "component_name": "HBASE_REGIONSERVER"
@@ -180,11 +180,11 @@
           "values": [
             {
               "name": "Active Handlers",
-              "value": "${ipc.IPC.numActiveHandler}"
+              "value": "${regionserver.RegionServer.numActiveHandler}"
             },
             {
               "name": "Calls in General Queue",
-              "value": "${ipc.IPC.numCallsInGeneralQueue}"
+              "value": "${regionserver.RegionServer.numCallsInGeneralQueue}"
             }
           ],
           "properties": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/widgets.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/widgets.json b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/widgets.json
index 622ee03..15b983a 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/widgets.json
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/widgets.json
@@ -7,7 +7,7 @@
       "widgetLayoutInfo": [
         {
           "widget_name": "GC_STATISTICS",
-          "display_name": "Garbage Collection Statistics",
+          "display_name": "GC Statistics",
           "description": "This widget shows JVM Garbage collection statistics for Active NameNode",
           "widget_type": "GRAPH",
           "is_visible": true,
@@ -287,7 +287,7 @@
           "metrics": [
             {
               "name": "dfs.datanode.BytesWritten",
-              "metric_path": "metrics/dfs/datanode/bytes_read",
+              "metric_path": "metrics/dfs/datanode/bytes_written",
               "service_name": "HDFS",
               "component_name": "DATANODE"
             }

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/widgets.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/widgets.json b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/widgets.json
index a9e233f..9721b91 100644
--- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/widgets.json
+++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/widgets.json
@@ -210,7 +210,7 @@
         },
         {
           "widget_name": "YARN_MEMORY_USED",
-          "display_name": "YARN Memory used %",
+          "display_name": "NodeManager Memory used %",
           "description": "",
           "widget_type": "HEATMAP",
           "is_visible": false,
@@ -230,7 +230,7 @@
           ],
           "values": [
             {
-              "name": "YARN Memory used %",
+              "name": "NodeManager Memory used %",
               "value": "${yarn.NodeManagerMetrics.AllocatedGB/(yarn.NodeManagerMetrics.AvailableGB + yarn.NodeManagerMetrics.AllocatedGB)}"
             }
           ],

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-server/src/main/resources/stacks/HDP/2.0.6/widgets.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/widgets.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/widgets.json
index 7935750..2343616 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/widgets.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/widgets.json
@@ -3,7 +3,7 @@
     {
       "layout_name": "default_system_heatmap",
       "display_name": "Heatmaps",
-      "section_name": "SYSTEM_METRICS_HEATMAPS",
+      "section_name": "SYSTEM_HEATMAPS",
       "widgetLayoutInfo": [
         {
           "widget_name": "HOST_DISK_USED",

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/widgets.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/widgets.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/widgets.json
index 1212133..19bd480 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/widgets.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/HBASE/widgets.json
@@ -145,7 +145,7 @@
           "is_visible": true,
           "metrics": [
             {
-              "name": "ipc.IPC.numOpenConnections",
+              "name": "regionserver.RegionServer.numOpenConnections",
               "metric_path": "metrics/hbase/ipc/IPC/numOpenConnections",
               "category": "",
               "service_name": "HBASE",
@@ -155,7 +155,7 @@
           "values": [
             {
               "name": "Open Connections",
-              "value": "${ipc.IPC.numOpenConnections}"
+              "value": "${regionserver.RegionServer.numOpenConnections}"
             }
           ],
           "properties": {
@@ -171,13 +171,13 @@
           "is_visible": true,
           "metrics": [
             {
-              "name": "ipc.IPC.numActiveHandler",
+              "name": "regionserver.RegionServer.numActiveHandler",
               "metric_path": "metrics/hbase/ipc/IPC/numActiveHandler",
               "service_name": "HBASE",
               "component_name": "HBASE_REGIONSERVER"
             },
             {
-              "name": "ipc.IPC.numCallsInGeneralQueue",
+              "name": "regionserver.RegionServer.numCallsInGeneralQueue",
               "metric_path": "metrics/hbase/ipc/IPC/numCallsInGeneralQueue",
               "service_name": "HBASE",
               "component_name": "HBASE_REGIONSERVER"
@@ -186,11 +186,11 @@
           "values": [
             {
               "name": "Active Handlers",
-              "value": "${ipc.IPC.numActiveHandler}"
+              "value": "${regionserver.RegionServer.numActiveHandler}"
             },
             {
               "name": "Calls in General Queue",
-              "value": "${ipc.IPC.numCallsInGeneralQueue}"
+              "value": "${regionserver.RegionServer.numCallsInGeneralQueue}"
             }
           ],
           "properties": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/assets/data/widget_layouts/HBASE/default_dashboard.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/widget_layouts/HBASE/default_dashboard.json b/ambari-web/app/assets/data/widget_layouts/HBASE/default_dashboard.json
index 9374ab0..8b30c81 100644
--- a/ambari-web/app/assets/data/widget_layouts/HBASE/default_dashboard.json
+++ b/ambari-web/app/assets/data/widget_layouts/HBASE/default_dashboard.json
@@ -36,7 +36,7 @@
               "author": "ambari",
               "description": "This widget shows 95th percentile of the read latency.",
               "scope": "CLUSTER",
-              "properties": "{\"display_unit\":\"%\"}",
+              "properties": "{\"display_unit\":\"\"}",
               "widget_name": "READ_LATENCY_95",
               "widget_type": "NUMBER",
               "time_created": 1428990958952,
@@ -53,7 +53,7 @@
               "author": "ambari",
               "description": "This widget shows 95th percentile of the write latency.",
               "scope": "CLUSTER",
-              "properties": "{\"display_unit\":\"%\"}",
+              "properties": "{\"display_unit\":\"\"}",
               "widget_name": "WRITE_LATENCY_95",
               "widget_type": "NUMBER",
               "time_created": 1428990958952,

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/assets/data/widget_layouts/all_heatmaps.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/widget_layouts/all_heatmaps.json b/ambari-web/app/assets/data/widget_layouts/all_heatmaps.json
new file mode 100644
index 0000000..903ebc4
--- /dev/null
+++ b/ambari-web/app/assets/data/widget_layouts/all_heatmaps.json
@@ -0,0 +1,258 @@
+
+{
+  "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets?WidgetInfo/widget_type=HEATMAP&WidgetInfo/scope=CLUSTER",
+  "items" : [
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/1",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "Host Disk Space Used %",
+        "id" : 1,
+        "scope" : "CLUSTER",
+        "widget_name" : "HOST_DISK_USED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/2",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "Host Memory Used %",
+        "id" : 2,
+        "scope" : "CLUSTER",
+        "widget_name" : "HOST_MEMORY_USED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/3",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "Host CPU Wait IO %",
+        "id" : 3,
+        "scope" : "CLUSTER",
+        "widget_name" : "HOST_CPU_WAIT_IO",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/12",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HDFS Bytes Read",
+        "id" : 12,
+        "scope" : "CLUSTER",
+        "widget_name" : "HDFS_BYTES_READ",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/13",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HDFS Bytes Written",
+        "id" : 13,
+        "scope" : "CLUSTER",
+        "widget_name" : "HDFS_BYTES_WRITE",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/14",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "DataNode Garbage Collection Time",
+        "id" : 14,
+        "scope" : "CLUSTER",
+        "widget_name" : "DN_GC_TIME",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/15",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "DataNode JVM Heap Memory Used",
+        "id" : 15,
+        "scope" : "CLUSTER",
+        "widget_name" : "DN_JVM_HEAP_USED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/16",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "DataNode JVM Heap Memory Committed",
+        "id" : 16,
+        "scope" : "CLUSTER",
+        "widget_name" : "DN_JVM_HEAP_COMMITTED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/17",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "DataNode Process Disk I/O Utilization",
+        "id" : 17,
+        "scope" : "CLUSTER",
+        "widget_name" : "DN_DISK_IO",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/18",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "DataNode Process Network I/O Utilization",
+        "id" : 18,
+        "scope" : "CLUSTER",
+        "widget_name" : "DN_NETWORK_IO",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/23",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "NodeManager Garbage Collection Time",
+        "id" : 23,
+        "scope" : "CLUSTER",
+        "widget_name" : "NM_GC_TIME",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/24",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "NodeManager JVM Heap Memory Used",
+        "id" : 24,
+        "scope" : "CLUSTER",
+        "widget_name" : "NM_JVM_Heap_Used",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/25",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "YARN Memory used %",
+        "id" : 25,
+        "scope" : "CLUSTER",
+        "widget_name" : "YARN_MEMORY_USED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/26",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "Allocated Containers",
+        "id" : 26,
+        "scope" : "CLUSTER",
+        "widget_name" : "ALLOCATED_CONTAINER",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/27",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "NodeManager RAM Utilized",
+        "id" : 27,
+        "scope" : "CLUSTER",
+        "widget_name" : "NM_RAM_UTILIZED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/28",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "NodeManager CPU Utilized",
+        "id" : 28,
+        "scope" : "CLUSTER",
+        "widget_name" : "NM_CPU_UTILIZED",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/37",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HBase Compaction Queue Size",
+        "id" : 37,
+        "scope" : "CLUSTER",
+        "widget_name" : "HBASE_COMPACTION_QUEUE_SIZE",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/38",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HBase Memstore Sizes",
+        "id" : 38,
+        "scope" : "CLUSTER",
+        "widget_name" : "HBASE_MEMSTORE_SIZES",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/39",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HBase Read Request Count",
+        "id" : 39,
+        "scope" : "CLUSTER",
+        "widget_name" : "HBASE_READ_REQUEST",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/40",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HBase Write Request Count",
+        "id" : 40,
+        "scope" : "CLUSTER",
+        "widget_name" : "HBASE_WRITE_REQUEST",
+        "widget_type" : "HEATMAP"
+      }
+    },
+    {
+      "href" : "http://104.196.82.37:8080/api/v1/clusters/c1/widgets/41",
+      "WidgetInfo" : {
+        "author" : "ambari",
+        "cluster_name" : "c1",
+        "display_name" : "HBase Regions",
+        "id" : 41,
+        "scope" : "CLUSTER",
+        "widget_name" : "HBASE_REGIONS",
+        "widget_type" : "HEATMAP"
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index 27aaf95..14a0ea8 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -73,16 +73,6 @@ var files = ['test/init_model_test',
   'test/controllers/main/dashboard/config_history_controller_test',
   'test/controllers/main/charts/heatmap_test',
   'test/controllers/main/charts/heatmap_metrics/heatmap_metric_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed_test',
-  'test/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun_test',
   'test/controllers/main/alerts/manage_alert_groups_controller_test',
   'test/controllers/main/host/add_controller_test',
   'test/controllers/main/host/configs_service_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 0777187..1540ae8 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -118,25 +118,6 @@ require('controllers/main/host/addHost/step4_controller');
 require('controllers/main/host/host_alerts_controller');
 require('controllers/main/charts');
 require('controllers/main/charts/heatmap_metrics/heatmap_metric');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_processrun');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_gctime');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_memHeapUsed');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_gctime');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_memHeapUsed');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_readrequest');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_writerequest');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_compactionqueue');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_regions');
-require('controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_memstoresize');
 require('controllers/main/charts/heatmap');
 require('controllers/main/service/info/heatmap');
 require('controllers/main/views_controller');

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap.js b/ambari-web/app/controllers/main/charts/heatmap.js
index 02ccbed..8404c2a 100644
--- a/ambari-web/app/controllers/main/charts/heatmap.js
+++ b/ambari-web/app/controllers/main/charts/heatmap.js
@@ -17,35 +17,148 @@
 
 var App = require('app');
 
-App.MainChartsHeatmapController = Em.Controller.extend({
+App.MainChartsHeatmapController = Em.Controller.extend(App.WidgetSectionMixin, {
   name: 'mainChartsHeatmapController',
-  rackMap: [],
-  modelRacks: [],
+  rackMap: {},
+  racks: [],
   rackViews: [],
+
+  /**
+   * Heatmap metrics that are available choices  on the page
+   */
+  heatmapCategories: [],
+
+  allHeatmaps:[],
+
+  layoutNameSuffix: "_heatmap",
+
+  sectionNameSuffix: "_HEATMAPS",
+
   loadRacksUrlParams: 'fields=Hosts/rack_info,Hosts/host_name,Hosts/public_host_name,Hosts/os_type,Hosts/ip,host_components,metrics/disk,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free&minimal_response=true',
 
-  racks: function () {
-    return this.get('modelRacks');
-  }.property('modelRacks.@each.isLoaded'),
+  loadHeatmapsUrlParams: function() {
+    var serviceName = this.get('content.serviceName');
+    if (serviceName) {
+      return 'WidgetInfo/widget_type=HEATMAP&WidgetInfo/scope=CLUSTER&WidgetInfo/metrics.matches(.*\"service_name\":\"' + serviceName + '\".*)&fields=WidgetInfo/metrics';
+    } else {
+      return 'WidgetInfo/widget_type=HEATMAP&WidgetInfo/scope=CLUSTER&fields=WidgetInfo/metrics';
+    }
+  }.property('content.serviceName'),
+
+
+  selectedMetric: null,
+
+  inputMaximum: '',
+
+  /**
+   * Heatmap widget currently shown on the page
+   */
+  activeWidget: function() {
+    if (this.get('widgets') && this.get('widgets').length) {
+      return this.get('widgets')[0];
+    } else {
+      return false;
+    }
+  }.property('widgets.@each'),
+
+
+  /**
+   * This function is called from the binded view of the controller
+   */
+  loadPageData: function() {
+    var self = this;
+    this.resetPageData();
+    this.getAllHeatMaps().done(function(allHeatmapData){
+      allHeatmapData.items.forEach(function(_allHeatmapData) {
+        self.get('allHeatmaps').pushObject(_allHeatmapData.WidgetInfo);
+      });
+      var categories = self.categorizeByServiceName(self.get('allHeatmaps'));
+      self.set('heatmapCategories', categories);
+      self.loadActiveWidgetLayout();
+    });
+  },
+
+  /**
+   * categorize heatmaps with respect to service names
+   * @param {Array} allHeatmaps
+   * @return {Array}
+   */
+  categorizeByServiceName: function(allHeatmaps) {
+  var categories = [];
+    allHeatmaps.forEach(function(_heatmap){
+    var serviceNames = JSON.parse(_heatmap.metrics).mapProperty('service_name').uniq();
+      serviceNames.forEach(function(_serviceName){
+        var category = categories.findProperty('serviceName',_serviceName);
+        if (!category) {
+          categories.pushObject(Em.Object.create({
+            serviceName: _serviceName,
+            displayName: _serviceName === 'STACK' ? 'Host' : App.StackService.find().findProperty('serviceName',_serviceName).get('displayName'),
+            heatmaps: [_heatmap]
+          }));
+        } else {
+          category.get('heatmaps').pushObject(_heatmap);
+        }
+      },this);
+    },this);
+    return categories;
+  },
+
+  /**
+   * clears/resets the data. This function should be called every time user navigates to heatmap page
+   */
+  resetPageData: function() {
+    this.get('heatmapCategories').clear();
+    this.get('allHeatmaps').clear();
+  },
+
+  /**
+   * success callback of <code>loadActiveWidgetLayout()</code>
+   * @overrriden
+   * @param {object|null} data
+   */
+  loadActiveWidgetLayoutSuccessCallback: function (data) {
+    if (data.items[0]) {
+      App.widgetMapper.map(data.items[0].WidgetLayoutInfo);
+      App.widgetLayoutMapper.map(data);
+      this.set('activeWidgetLayout', App.WidgetLayout.find().findProperty('layoutName', this.get('defaultLayoutName')));
+      this.set('isWidgetsLoaded', true);
+    }
+  },
+
+  /**
+   *  Gets all heatmap widgets that should be available in select metrics dropdown on heatmap page
+   * @return {$.ajax}
+   */
+  getAllHeatMaps: function() {
+    var urlParams = this.get('loadHeatmapsUrlParams');
+
+    return App.ajax.send({
+      name: 'widgets.get',
+      sender: this,
+      data: {
+        urlParams: urlParams
+      }
+    });
+  },
+
 
   /**
    * get hosts from server
    */
   loadRacks: function () {
-    this.get('modelRacks').clear();
-    this.get('rackMap').clear();
+    this.get('racks').clear();
+    this.set('rackMap', {});
     var urlParams = this.get('loadRacksUrlParams');
-    App.ajax.send({
+    return App.ajax.send({
       name: 'hosts.heatmaps',
       sender: this,
       data: {
         urlParams: urlParams
-      },
-      success: 'getHostsSuccessCallback'
+      }
     });
   },
 
-  getHostsSuccessCallback: function (data, opt, params) {
+  loadRacksSuccessCallback: function (data, opt, params) {
     var hosts = [];
     data.items.forEach(function (item) {
       hosts.push({
@@ -64,14 +177,14 @@ App.MainChartsHeatmapController = Em.Controller.extend({
       });
     });
     var rackMap = this.indexByRackId(hosts);
-    var modelRacks = this.toList(rackMap);
+    var racks = this.toList(rackMap);
     //this list has an empty host array property
     this.set('rackMap', rackMap);
-    this.set('modelRacks', modelRacks);
+    this.set('racks', racks);
   },
 
   indexByRackId: function (hosts) {
-    var rackMap = [];
+    var rackMap = {};
     hosts.forEach(function (host) {
       var rackId = host.rack;
       if(!rackMap[rackId]) {
@@ -97,7 +210,7 @@ App.MainChartsHeatmapController = Em.Controller.extend({
           Em.Object.create({
             name: rackKey,
             rackId: rackKey,
-            hosts: [],
+            hosts: rackMap[rackKey].hosts,
             isLoaded: false,
             index: i++
           })
@@ -107,25 +220,6 @@ App.MainChartsHeatmapController = Em.Controller.extend({
     return racks;
   },
 
-  allMetrics: function () {
-    var metrics = [];
-
-    // Display host heatmaps if the stack definition has a host metrics service to display it.
-    if(App.get('services.hostMetrics').length) {
-      metrics.pushObjects([
-        App.MainChartHeatmapDiskSpaceUsedMetric.create(),
-        App.MainChartHeatmapMemoryUsedMetric.create(),
-        App.MainChartHeatmapCpuWaitIOMetric.create()
-      ]);
-    }
-
-    return metrics;
-  }.property(),
-
-  selectedMetric: null,
-
-  inputMaximum: '',
-
   validation: function () {
     if (this.get('selectedMetric')) {
       if (/^\d+$/.test(this.get('inputMaximum'))) {
@@ -140,7 +234,7 @@ App.MainChartsHeatmapController = Em.Controller.extend({
 
   addRackView: function (view) {
     this.get('rackViews').push(view);
-    if (this.get('rackViews').length == this.get('modelRacks').length) {
+    if (this.get('rackViews').length == this.get('racks').length) {
       this.displayAllRacks();
     }
   },
@@ -153,28 +247,17 @@ App.MainChartsHeatmapController = Em.Controller.extend({
   },
 
   showHeatMapMetric: function (event) {
-    var metricItem = event.context;
-    if (metricItem) {
-      this.set('selectedMetric', metricItem);
-    }
+    var self = this;
+    var metricItem = Em.Object.create(event.context);
+    this.saveWidgetLayout([metricItem]).done(function(){
+      self.loadActiveWidgetLayout();
+    });
   },
 
   hostToSlotMap: function () {
     return this.get('selectedMetric.hostToSlotMap');
   }.property('selectedMetric.hostToSlotMap'),
 
-  loadMetrics: function () {
-    var selectedMetric = this.get('selectedMetric');
-    var hostNames = [];
-    if (selectedMetric && this.get('racks').everyProperty('isLoaded', true)) {
-      this.get('racks').forEach(function (rack) {
-        hostNames = hostNames.concat(rack.hosts.mapProperty('hostName'));
-      });
-      selectedMetric.refreshHostSlots(hostNames);
-    }
-    this.set('inputMaximum', this.get('selectedMetric.maximumValue'));
-  }.observes('selectedMetric'),
-
   /**
    * return class name for to be used for containing each rack.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js
index c4a7b95..58874ef 100644
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js
+++ b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric.js
@@ -32,7 +32,7 @@ var heatmap = require('utils/heatmap');
  * </ul>
  * 
  */
-App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
+App.MainChartHeatmapMetric = Em.Object.extend({
   /**
    * Name of this metric
    */
@@ -93,11 +93,6 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
    */
   units: '',
 
-  /**
-   * Indicates whether this metric is currently loading data from the server.
-   * {Boolean}
-   */
-  loading: false,
 
   /**
    * Provides following information about slots in an array of objects.
@@ -199,51 +194,6 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
    */
   slotDefinitionLabelSuffix: '',
 
-  defaultMetric: '',
-
-  /**
-   * Name in the <code>App.ajax</code>
-   * @type {String}
-   */
-  ajaxIndex: 'hosts.metrics',
-
-  /**
-   * Additional data for ajax-request
-   * May be redeclared in child-objects
-   * @type {Object}
-   */
-  ajaxData: {},
-
-  /**
-   * Maps server JSON into an object where keys are hostnames and values are the
-   * true metric values. This function by default will map 'defaultMetric' into
-   * its corresponding value.
-   * 
-   * @Function
-   */
-  metricMapper: function (json) {
-    var hostToValueMap = {};
-    var metricName = this.get('defaultMetric');
-    if (json.items) {
-      var props = metricName.split('.');
-      json.items.forEach(function (item) {
-        var value = item;
-        props.forEach(function (prop) {
-          if (value != null && prop in value) {
-            value = value[prop];
-          } else {
-            value = null;
-          }
-        });
-        if (value != null) {
-          var hostName = item.Hosts.host_name;
-          hostToValueMap[hostName] = value;
-        }
-      });
-    }
-    return hostToValueMap;
-  },
-
   hostToValueMap: null,
 
   hostToSlotMap: function () {
@@ -252,7 +202,7 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
     var hostToSlotMap = {};
     if (hostToValueMap && hostNames) {
       hostNames.forEach(function (hostName) {
-        var slot = this.calculateSlot(hostToValueMap, hostName)
+        var slot = this.calculateSlot(hostToValueMap, hostName);
         if (slot > -1) {
           hostToSlotMap[hostName] = slot;
         }
@@ -294,40 +244,6 @@ App.MainChartHeatmapMetric = Em.Object.extend(heatmap.mappers, {
   },
 
   /**
-   * Determines which slot each host falls into. This information is given to
-   * the callback's #map(hostnameToSlotObject) method. The
-   * 'hostnameToSlotObject' has key as hostname, and the slot index as value.
-   */
-  refreshHostSlots: function (hostNames) {
-    this.set('loading', true);
-    this.set('hostNames', hostNames);
-    var fixedMetricName = this.get('defaultMetric');
-    fixedMetricName = fixedMetricName.replace(/\./g, "/");
-    var ajaxData = {
-      metricName: fixedMetricName
-    };
-    jQuery.extend(ajaxData, this.get('ajaxData'));
-
-    App.ajax.send({
-      name: this.get('ajaxIndex'),
-      sender: this,
-      data: ajaxData,
-      success: 'refreshHostSlotsSuccessCallback',
-      error: 'refreshHostSlotsErrorCallback'
-    });
-  },
-
-  refreshHostSlotsSuccessCallback: function (data) {
-    var hostToValueMap = this.metricMapper(data);
-    this.set('hostToValueMap', hostToValueMap);
-    this.set('loading', false);
-  },
-
-  refreshHostSlotsErrorCallback: function () {
-    this.set('loading', false);
-  },
-
-  /**
    * Turns numbers into displayable values. For example 24.345432425 into 24.3
    * etc.
    * 

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO.js
deleted file mode 100644
index 35bb947..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_cpuWaitIO.js
+++ /dev/null
@@ -1,39 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapCpuWaitIOMetric = App.MainChartHeatmapMetric.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.cpuWaitIO'),
-  maximumValue: 100,
-  defaultMetric: 'metrics.cpu.cpu_wio',
-  units: '%',
-  slotDefinitionLabelSuffix: '%',
-  metricMapper: function (json) {
-    var map = this._super(json);
-    for ( var host in map) {
-      if (host in map) {
-        var val = map[host];
-        map[host] = (val * 100).toFixed(1);
-      }
-    }
-    return map;
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs.js
deleted file mode 100644
index 100a65e..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs.js
+++ /dev/null
@@ -1,45 +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.
- */
-
-var App = require('app');
-
-/**
- * Base class for any HDFS metric.
- */
-App.MainChartHeatmapDFSMetrics = App.MainChartHeatmapMetric.extend({
-
-  ajaxIndex: 'hosts.metrics.host_component',
-
-  ajaxData: {
-    serviceName: 'HDFS',
-    componentName: 'DATANODE'
-  },
-
-  /**
-   * Custom mapper for DFS metrics
-   */
-  metricMapper: function(json) {
-    return this.metricMapperWithTransform(json, this.get('defaultMetric'), this.get('transformValue'));
-  },
-  /**
-   * Utility function which allows extending classes to transform the value
-   * assigned to a host.
-   * 
-   * @Function
-   */
-  transformValue: null
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread.js
deleted file mode 100644
index 0d28eb0b..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_bytesread.js
+++ /dev/null
@@ -1,32 +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.
- */
-
-var App = require('app');
-
-/**
- * 
- */
-App.MainChartHeatmapDFSBytesReadMetric = App.MainChartHeatmapDFSMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.bytesRead'),
-  maximumValue: 1024, // 1GB
-  defaultMetric: 'metrics.dfs.datanode.bytes_read',
-  units: 'MB',
-  slotDefinitionLabelSuffix: 'MB',
-  transformValue: function (value) {
-    return value / (1024 * 1024); // bytes divided by 1MB.
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten.js
deleted file mode 100644
index 9306241..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_byteswritten.js
+++ /dev/null
@@ -1,32 +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.
- */
-
-var App = require('app');
-
-/**
- * 
- */
-App.MainChartHeatmapDFSBytesWrittenMetric = App.MainChartHeatmapDFSMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.bytesWritten'),
-  maximumValue: 1024, // 1GB
-  defaultMetric: 'metrics.dfs.datanode.bytes_written',
-  units: 'MB',
-  slotDefinitionLabelSuffix: 'MB',
-  transformValue: function (value) {
-    return value / (1024 * 1024); // bytes divided by 1MB.
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_gctime.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_gctime.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_gctime.js
deleted file mode 100644
index c39393f..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_gctime.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- * 
- */
-App.MainChartHeatmapDFSGCTimeMillisMetric = App.MainChartHeatmapDFSMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.DFSGarbageCollection'),
-  maximumValue: 10000,
-  defaultMetric: 'metrics.jvm.gcTimeMillis',
-  units: ' ms',
-  slotDefinitionLabelSuffix: ' ms'
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_memHeapUsed.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_memHeapUsed.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_memHeapUsed.js
deleted file mode 100644
index 18ae47b..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_dfs_memHeapUsed.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- * 
- */
-App.MainChartHeatmapDFSMemHeapUsedMetric = App.MainChartHeatmapDFSMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.DFSMemHeapUsed'),
-  maximumValue: 512,
-  defaultMetric: 'metrics.jvm.memHeapUsedM',
-  units: 'MB',
-  slotDefinitionLabelSuffix: 'MB'
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused.js
deleted file mode 100644
index 403e034..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_diskspaceused.js
+++ /dev/null
@@ -1,65 +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.
- */
-
-var App = require('app');
-
-/**
- * 
- */
-App.MainChartHeatmapDiskSpaceUsedMetric = App.MainChartHeatmapMetric.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.diskSpaceUsed'),
-  maximumValue: 100,
-  defaultMetric: 'metrics.disk',
-  units: '%',
-  slotDefinitionLabelSuffix: '%',
-  metricMapper: function (json) {
-    var hostToValueMap = {};
-    var self = this;
-    var metricName = this.get('defaultMetric');
-    if (json.items) {
-      var props = metricName.split('.');
-      json.items.forEach(function (item) {
-        var value = item;
-        props.forEach(function (prop) {
-          if (value != null && prop in value) {
-            value = value[prop];
-          } else {
-            value = null;
-          }
-        });
-        if (value != null) {
-          value = self.diskUsageFormatted(value.disk_total - value.disk_free, value.disk_total);
-          var hostName = item.Hosts.host_name;
-          hostToValueMap[hostName] = value;
-        }
-      });
-    }
-    return hostToValueMap;
-  },
-
-  /**
-   * Format percent disk usage to float with 2 digits
-   */
-  diskUsageFormatted: function(diskUsed, diskTotal) {
-    var diskUsage = (diskUsed) / diskTotal * 100;
-    if (isNaN(diskUsage) || diskUsage < 0 || diskUsage > 100) {
-      return Em.I18n.t('charts.heatmap.unknown');
-    }
-    var s = Math.round(diskUsage * Math.pow(10, 2)) / Math.pow(10, 2);
-    return isNaN(s) ? 0 : s;
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase.js
deleted file mode 100644
index 9b1fc4a..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase.js
+++ /dev/null
@@ -1,46 +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.
- */
-
-var App = require('app');
-
-/**
- * Base class for any HDFS metric.
- */
-App.MainChartHeatmapHbaseMetrics = App.MainChartHeatmapMetric.extend({
-
-  ajaxIndex: 'hosts.metrics.host_component',
-
-  ajaxData: {
-    serviceName: 'HBASE',
-    componentName: 'HBASE_REGIONSERVER'
-  },
-
-  /**
-   * Custom mapper for HBase metrics
-   */
-  metricMapper: function(json) {
-    return this.metricMapperWithTransform(json, this.get('defaultMetric'), this.get('transformValue'));
-  },
-
-  /**
-   * Utility function which allows extending classes to transform the value
-   * assigned to a host.
-   *
-   * @Function
-   */
-  transformValue: null
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_compactionqueue.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_compactionqueue.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_compactionqueue.js
deleted file mode 100644
index 09cb300..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_compactionqueue.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapHbaseCompactionQueueSize = App.MainChartHeatmapHbaseMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.HbaseRegionServerCompactionQueueSize'),
-  maximumValue: 10,
-  defaultMetric: 'metrics.hbase.regionserver.compactionQueueSize',
-  units: '',
-  slotDefinitionLabelSuffix: ''
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_memstoresize.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_memstoresize.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_memstoresize.js
deleted file mode 100644
index a4eed4e..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_memstoresize.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapHbaseMemStoreSize = App.MainChartHeatmapHbaseMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.HbaseRegionServerMemStoreSize'),
-  maximumValue: 100*1024*1024,
-  defaultMetric: 'metrics.hbase.regionserver.memstoreSize',
-  units: 'B',
-  slotDefinitionLabelSuffix: 'B'
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_readrequest.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_readrequest.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_readrequest.js
deleted file mode 100644
index 6f914e6..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_readrequest.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapHbaseReadReqCount = App.MainChartHeatmapHbaseMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.HbaseRegionServerReadCount'),
-  maximumValue: 200,
-  defaultMetric: 'metrics.hbase.regionserver.readRequestsCount',
-  units: '',
-  slotDefinitionLabelSuffix: ''
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_regions.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_regions.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_regions.js
deleted file mode 100644
index a2c2c11..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_regions.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapHbaseRegions = App.MainChartHeatmapHbaseMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.HbaseRegionServerRegions'),
-  maximumValue: 10,
-  defaultMetric: 'metrics.hbase.regionserver.regions',
-  units: '',
-  slotDefinitionLabelSuffix: ''
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_writerequest.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_writerequest.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_writerequest.js
deleted file mode 100644
index f81ab63..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_hbase_writerequest.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapHbaseWriteReqCount = App.MainChartHeatmapHbaseMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.HbaseRegionServerWriteCount'),
-  maximumValue: 200,
-  defaultMetric: 'metrics.hbase.regionserver.writeRequestsCount',
-  units: '',
-  slotDefinitionLabelSuffix: ''
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused.js
deleted file mode 100644
index 335966d..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_memoryused.js
+++ /dev/null
@@ -1,63 +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.
- */
-
-var App = require('app');
-
-/**
- * Base class for any heatmap metric.
- * 
- * This class basically provides the following for each heatmap metric.
- * <ul>
- * <li> Provides number of slots in which temperature can fall.
- * <li> Maintains the maximum value so as to scale slot ranges.
- * <li> Gets JSON data from server and maps response for all hosts into above
- * slots.
- * </ul>
- * 
- */
-App.MainChartHeatmapMemoryUsedMetric = App.MainChartHeatmapMetric.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.memoryUsed'),
-  maximumValue: 100,
-  defaultMetric: 'metrics.memory',
-  units: '%',
-  slotDefinitionLabelSuffix: '%',
-  metricMapper: function (json) {
-    var hostToValueMap = {};
-    var metricName = this.get('defaultMetric');
-    if (json.items) {
-      var props = metricName.split('.');
-      json.items.forEach(function (item) {
-        var value = item;
-        props.forEach(function (prop) {
-          if (value != null && prop in value) {
-            value = value[prop];
-          } else {
-            value = null;
-          }
-        });
-        if (value != null) {
-          var total = value.mem_total;
-          var used = value.mem_total - value.mem_free - value.mem_cached;
-          value = ((used * 100) / total).toFixed(1);
-          var hostName = item.Hosts.host_name;
-          hostToValueMap[hostName] = value;
-        }
-      });
-    }
-    return hostToValueMap;
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun.js
deleted file mode 100644
index 20de918..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_processrun.js
+++ /dev/null
@@ -1,45 +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.
- */
-
-var App = require('app');
-
-/**
- * Base class for any heatmap metric.
- *
- * This class basically provides the following for each heatmap metric.
- * <ul>
- * <li> Provides number of slots in which temperature can fall.
- * <li> Maintains the maximum value so as to scale slot ranges.
- * <li> Gets JSON data from server and maps response for all hosts into above
- * slots.
- * </ul>
- *
- */
-App.MainChartHeatmapProcessRunMetric = App.MainChartHeatmapMetric.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.processRun'),
-  maximumValue: 1,
-  defaultMetric: 'metrics.process.proc_run',
-  units: 'Processes',
-  metricMapper: function (json) {
-    var map = this._super(json);
-    for (var host in map) {
-      var val = map[host];
-      map[host] = val.toFixed(1);
-    }
-    return map;
-  }
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn.js
deleted file mode 100644
index f60075d..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn.js
+++ /dev/null
@@ -1,46 +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.
- */
-
-var App = require('app');
-
-/**
- * Base class for any YARN metric.
- */
-App.MainChartHeatmapYarnMetrics = App.MainChartHeatmapMetric.extend({
-
-  ajaxIndex: 'hosts.metrics.host_component',
-
-  ajaxData: {
-    serviceName: 'YARN',
-    componentName: 'NODEMANAGER'
-  },
-
-  /**
-   * Custom mapper for YARN metrics
-   */
-  metricMapper: function(json) {
-    return this.metricMapperWithTransform(json, this.get('defaultMetric'), this.get('transformValue'));
-  },
-
-  /**
-   * Utility function which allows extending classes to transform the value
-   * assigned to a host.
-   *
-   * @Function
-   */
-  transformValue: null
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed.js
deleted file mode 100644
index f0ee406..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_ResourceUsed.js
+++ /dev/null
@@ -1,66 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapYarnResourceUsedMetric = App.MainChartHeatmapYarnMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.YarnMemoryUsed'),
-  maximumValue: 100,
-  defaultMetric: 'metrics.yarn',
-  units: ' %',
-  slotDefinitionLabelSuffix: ' %',
-
-  metricMapper: function (json) {
-    var hostToValueMap = {};
-    var self = this;
-    var metricName = this.get('defaultMetric');
-    if (json.host_components) {
-      var props = metricName.split('.');
-      json.host_components.forEach(function (host) {
-        var value = host;
-        props.forEach(function (prop) {
-          if (value != null && prop in value) {
-            value = value[prop];
-          } else {
-            value = null;
-          }
-        });
-        if (value != null) {
-          value = self.memoryUsageFormatted(value.AllocatedGB, value.AvailableGB + value.AllocatedGB);
-          var hostName = host.HostRoles.host_name;
-          hostToValueMap[hostName] = value;
-        }
-      });
-    }
-    return hostToValueMap;
-  },
-
-  /**
-   * Format percent YARN memory used to float with 2 digits
-   */
-  memoryUsageFormatted: function(used, total) {
-    var usage = (used) / total * 100;
-    if (isNaN(usage) || usage < 0 || usage > 100) {
-      return Em.I18n.t('charts.heatmap.unknown');
-    }
-    var s = usage.toFixed(1);
-    return isNaN(s) ? 0 : s;
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_gctime.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_gctime.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_gctime.js
deleted file mode 100644
index 10efe65..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_gctime.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapYarnGCTimeMillisMetric = App.MainChartHeatmapYarnMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.YarnGCTime'),
-  maximumValue: 10000,
-  defaultMetric: 'metrics.jvm.gcTimeMillis',
-  units: ' ms',
-  slotDefinitionLabelSuffix: ' ms'
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_memHeapUsed.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_memHeapUsed.js b/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_memHeapUsed.js
deleted file mode 100644
index 762c0bf..0000000
--- a/ambari-web/app/controllers/main/charts/heatmap_metrics/heatmap_metric_yarn_memHeapUsed.js
+++ /dev/null
@@ -1,29 +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.
- */
-
-var App = require('app');
-
-/**
- *
- */
-App.MainChartHeatmapYarnMemHeapUsedMetric = App.MainChartHeatmapYarnMetrics.extend({
-  name: Em.I18n.t('charts.heatmap.metrics.YarnMemHeapUsed'),
-  maximumValue: 512,
-  defaultMetric: 'metrics.jvm.memHeapUsedM',
-  units: 'MB',
-  slotDefinitionLabelSuffix: 'MB'
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/service/info/heatmap.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/heatmap.js b/ambari-web/app/controllers/main/service/info/heatmap.js
index 467b8d7..2de6af0 100644
--- a/ambari-web/app/controllers/main/service/info/heatmap.js
+++ b/ambari-web/app/controllers/main/service/info/heatmap.js
@@ -17,36 +17,5 @@
  */
 var App = require('app');
 App.MainServiceInfoHeatmapController = App.MainChartsHeatmapController.extend({
-  name: 'mainServiceInfoHeatmapController',
-  allMetrics: function () {
-    var metrics = [];
-    var serviceName = this.get('content.serviceName');
-    switch (serviceName) {
-      case 'HDFS':
-        metrics.pushObjects([
-          App.MainChartHeatmapDFSBytesReadMetric.create(),
-          App.MainChartHeatmapDFSBytesWrittenMetric.create(),
-          App.MainChartHeatmapDFSGCTimeMillisMetric.create(),
-          App.MainChartHeatmapDFSMemHeapUsedMetric.create()
-        ]);
-        break;
-      case 'YARN':
-        metrics.pushObjects([
-          App.MainChartHeatmapYarnGCTimeMillisMetric.create(),
-          App.MainChartHeatmapYarnMemHeapUsedMetric.create(),
-          App.MainChartHeatmapYarnResourceUsedMetric.create()
-        ]);
-        break;
-      case 'HBASE':
-        metrics.pushObjects([
-          App.MainChartHeatmapHbaseReadReqCount.create(),
-          App.MainChartHeatmapHbaseWriteReqCount.create(),
-          App.MainChartHeatmapHbaseCompactionQueueSize.create(),
-          App.MainChartHeatmapHbaseRegions.create(),
-          App.MainChartHeatmapHbaseMemStoreSize.create()
-        ]);
-        break;
-    }
-    return metrics;
-  }.property('content.serviceName')
+  name: 'mainServiceInfoHeatmapController'
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/controllers/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/summary.js b/ambari-web/app/controllers/main/service/info/summary.js
index 882eade..4d902a6 100644
--- a/ambari-web/app/controllers/main/service/info/summary.js
+++ b/ambari-web/app/controllers/main/service/info/summary.js
@@ -17,7 +17,7 @@
 
 var App = require('app');
 
-App.MainServiceInfoSummaryController = Em.Controller.extend({
+App.MainServiceInfoSummaryController = Em.Controller.extend(App.WidgetSectionMixin, {
   name: 'mainServiceInfoSummaryController',
 
   selectedFlumeAgent: null,
@@ -40,29 +40,9 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
    */
   isPreviousRangerConfigsCallFailed: false,
 
-  /**
-   * UI section name
-   */
-  sectionName: function () {
-    return this.get('content.serviceName') + "_SUMMARY";
-  }.property('content.serviceName'),
-
-  /**
-   * UI default layout name
-   */
-  defaultLayoutName: function () {
-    return "default_" + this.get('content.serviceName').toLowerCase() + "_dashboard";
-  }.property('content.serviceName'),
+  layoutNameSuffix: "_dashboard",
 
-  /**
-   * Does Service has widget descriptor defined in the stack
-   * @type {boolean}
-   */
-  isServiceWithEnhancedWidgets: function () {
-    var serviceName = this.get('content.serviceName');
-    var stackService = App.StackService.find().findProperty('serviceName', serviceName);
-    return stackService.get('isServiceWithWidgets') && App.supports.customizedWidgets;
-  }.property('content.serviceName'),
+  sectionNameSuffix: "_SUMMARY",
 
   /**
    * Ranger plugins data
@@ -317,10 +297,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
     });
   },
 
-  /**
-   * @type {boolean}
-   */
-  isWidgetsLoaded: false,
 
   /**
    * @type {boolean}
@@ -337,24 +313,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
    */
   isMineWidgetsLoaded: false,
 
-  /**
-   *  @Type {App.WidgetLayout}
-   */
-  activeWidgetLayout: {},
-
-
-  /**
-   * @type {Em.A}
-   */
-  widgets: function () {
-    if (this.get('isWidgetsLoaded')) {
-      if (this.get('activeWidgetLayout.widgets')) {
-        return this.get('activeWidgetLayout.widgets').toArray();
-      } else {
-        return  [];
-      }
-    }
-  }.property('isWidgetsLoaded'),
 
   /**
    * @type {Em.A}
@@ -384,41 +342,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
     this.set('isWidgetLayoutsLoaded', true);
   },
 
-  /**
-   * load widgets defined by user
-   * @returns {$.ajax}
-   */
-  loadActiveWidgetLayout: function () {
-    this.set('activeWidgetLayout', {});
-    this.set('isWidgetsLoaded', false);
-    if (this.get('isServiceWithEnhancedWidgets')) {
-      return App.ajax.send({
-        name: 'widget.layout.get',
-        sender: this,
-        data: {
-          layoutName: this.get('defaultLayoutName'),
-          serviceName: this.get('content.serviceName')
-        },
-        success: 'loadActiveWidgetLayoutSuccessCallback'
-      });
-    } else {
-      this.set('isWidgetsLoaded', true);
-    }
-  },
-
-
-  /**
-   * success callback of <code>loadWidgets()</code>
-   * @param {object|null} data
-   */
-  loadActiveWidgetLayoutSuccessCallback: function (data) {
-    if (data.items[0]) {
-      App.widgetMapper.map(data.items[0].WidgetLayoutInfo);
-      App.widgetLayoutMapper.map(data);
-      this.set('activeWidgetLayout', App.WidgetLayout.find().findProperty('layoutName', this.get('defaultLayoutName')));
-      this.set('isWidgetsLoaded', true);
-    }
-  },
 
   /**
    * load all shared widgets to show on widget browser
@@ -525,7 +448,7 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
     });
     widgetIds.pushObject({
       "id": widgetToAdd.id
-    })
+    });
     var data = {
       "WidgetLayoutInfo": {
         "display_name": activeLayout.get("displayName"),
@@ -645,36 +568,6 @@ App.MainServiceInfoSummaryController = Em.Controller.extend({
   },
 
   /**
-   * save layout after re-order widgets
-   * return {$.ajax}
-   */
-  saveReorderedLayout: function (widgets) {
-    var activeLayout = this.get('activeWidgetLayout');
-    var data = {
-      "WidgetLayoutInfo": {
-        "display_name": activeLayout.get("displayName"),
-        "id": activeLayout.get("id"),
-        "layout_name": activeLayout.get("layoutName"),
-        "scope": activeLayout.get("scope"),
-        "section_name": activeLayout.get("sectionName"),
-        "widgets": widgets.map(function (widget) {
-          return {
-            "id": widget.get('id')
-          }
-        })
-      }
-    };
-    return App.ajax.send({
-      name: 'widget.layout.edit',
-      sender: this,
-      data: {
-        layoutId: activeLayout.get("id"),
-        data: data
-      }
-    });
-  },
-
-  /**
    * create widget
    */
   createWidget: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 5da43f9..2416384 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -2227,23 +2227,6 @@ Em.I18n.translations = {
   'charts.heatmap.unknown': 'Unknown',
   'charts.heatmap.label.notApplicable' :'Not Applicable',
   'charts.heatmap.label.invalidData' :'Invalid data',
-  'charts.heatmap.metrics.bytesRead' :'HDFS Bytes Read',
-  'charts.heatmap.metrics.bytesWritten' :'HDFS Bytes Written',
-  'charts.heatmap.metrics.DFSGarbageCollection' :'HDFS Garbage Collection Time',
-  'charts.heatmap.metrics.DFSMemHeapUsed' :'HDFS JVM Heap Memory Used',
-  'charts.heatmap.metrics.diskSpaceUsed' :'Host Disk Space Used %',
-  'charts.heatmap.metrics.YarnGCTime' :'YARN Garbage Collection Time',
-  'charts.heatmap.metrics.YarnMemHeapUsed' :'YARN JVM Heap Memory Used',
-
-  'charts.heatmap.metrics.memoryUsed' :'Host Memory Used %',
-  'charts.heatmap.metrics.processRun' :'Total Running Processes',
-  'charts.heatmap.metrics.YarnMemoryUsed' :'YARN Memory used %',
-  'charts.heatmap.metrics.cpuWaitIO':'Host CPU Wait I/O %',
-  'charts.heatmap.metrics.HbaseRegionServerReadCount': 'HBase Read Request Count',
-  'charts.heatmap.metrics.HbaseRegionServerWriteCount': 'HBase Write Request Count',
-  'charts.heatmap.metrics.HbaseRegionServerCompactionQueueSize': 'HBase Compaction Queue Size',
-  'charts.heatmap.metrics.HbaseRegionServerRegions': 'HBase Regions',
-  'charts.heatmap.metrics.HbaseRegionServerMemStoreSize': 'HBase Memstore Sizes',
   'metric.notFound':'no items found',
   'metric.default':'combined',
   'metric.cpu':'cpu',

http://git-wip-us.apache.org/repos/asf/ambari/blob/9639005f/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index a272c24..2ff5de8 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -45,6 +45,7 @@ require('mixins/wizard/wizard_menu_view');
 require('mixins/wizard/assign_master_components');
 require('mixins/common/configs/enhanced_configs');
 require('mixins/common/configs/configs_saver');
-require('mixins/common/widget_mixin');
+require('mixins/common/widgets/widget_mixin');
+require('mixins/common/widgets/widget_section');
 require('mixins/unit_convert/base_unit_convert_mixin');
 require('mixins/unit_convert/convert_unit_widget_view_mixin');