You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2016/10/05 12:37:06 UTC

[3/5] ambari git commit: AMBARI-18313. Capacity Scheduler View: Xml diff view tool to show changes made and queue capacity chart (Akhil PB via pallavkul)

AMBARI-18313. Capacity Scheduler View: Xml diff view tool to show changes made and queue capacity chart (Akhil PB via pallavkul)


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

Branch: refs/heads/branch-feature-AMBARI-18456
Commit: 62dc775ee4156e1a43ce0b991f3f47f68155128d
Parents: 26660f2
Author: Pallav Kulshreshtha <pa...@gmail.com>
Authored: Wed Oct 5 15:32:19 2016 +0530
Committer: Pallav Kulshreshtha <pa...@gmail.com>
Committed: Wed Oct 5 15:32:19 2016 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/components.js     |   2 +
 .../ui/app/components/labelCapacityBar.js       |  12 +-
 .../resources/ui/app/components/queueBadge.js   |   6 +-
 .../ui/app/components/queueHierarchy.js         |  11 +
 .../resources/ui/app/components/queueMapping.js |  25 +-
 .../resources/ui/app/components/queueSummary.js |  23 +-
 .../ui/app/components/sunburstChart.js          | 339 +++++++++++++++++++
 .../ui/app/components/xmldiffViewer.js          | 101 ++++++
 .../resources/ui/app/controllers/advanced.js    |  21 +-
 .../resources/ui/app/controllers/capsched.js    |  39 ++-
 .../resources/ui/app/controllers/editqueue.js   |  66 +++-
 .../resources/ui/app/controllers/queuesconf.js  | 106 +++++-
 .../resources/ui/app/controllers/scheduler.js   |  21 +-
 .../src/main/resources/ui/app/models/queue.js   |   9 +-
 .../src/main/resources/ui/app/router.js         |  49 ++-
 .../resources/ui/app/styles/application.less    |  59 ++++
 .../src/main/resources/ui/app/templates.js      |   2 +
 .../resources/ui/app/templates/capsched.hbs     |   6 +
 .../ui/app/templates/capsched/advanced.hbs      |  13 +-
 .../capsched/partials/accessControlList.hbs     |   4 +-
 .../capsched/partials/labelCapacity.hbs         |   4 +-
 .../templates/capsched/partials/preemption.hbs  |   4 +-
 .../capsched/partials/queueCapacity.hbs         |  34 +-
 .../capsched/partials/queueResources.hbs        |   4 +-
 .../ui/app/templates/capsched/queuesconf.hbs    |  15 +-
 .../ui/app/templates/capsched/scheduler.hbs     |   6 +-
 .../app/templates/components/queueHierarchy.hbs |   8 +-
 .../app/templates/components/queueMapping.hbs   |  14 +-
 .../app/templates/components/queueSummary.hbs   |  13 -
 .../app/templates/components/sunburstChart.hbs  |  44 +++
 .../app/templates/components/xmldiffViewer.hbs  |  41 +++
 .../src/main/resources/ui/bower.json            |  13 +-
 32 files changed, 1003 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components.js
index 8dd7108..8cf9a64 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components.js
@@ -39,3 +39,5 @@ require('components/editLabelCapacity');
 require('components/editQueueCapacity');
 require('components/labelCapacityBar');
 require('components/displayNodeLabels');
+require('components/xmldiffViewer');
+require('components/sunburstChart');

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js
index 7776452..032b2ec 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js
@@ -49,10 +49,14 @@ App.LabelCapacityBarComponent = Ember.Component.extend({
 
   warnInvalidLabelCapacity: function() {
     var totalCap = this.get('childrenQueueLabelsTotalCapacity');
-    var isInvalid = false;
-    if (totalCap > 100 || totalCap < 100) {
-      isInvalid = true;
-    }
+    var isInvalid = totalCap !== 100;
+    this.get('labels').forEach(function(label) {
+      if (isInvalid) {
+        label.set('overCapMessage', 'Invalid Total Capacity for label: '+label.get('name'));
+      } else {
+        label.set('overCapMessage', undefined);
+      }
+    });
     this.get('labels').setEach('overCapacity', isInvalid);
     this.set('warnInvalidTotalLabelCapacity', isInvalid);
     return isInvalid;

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueBadge.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueBadge.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueBadge.js
index f8978c2..0403b3d 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueBadge.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueBadge.js
@@ -34,11 +34,13 @@ App.WarningInfoComponent = Em.Component.extend({
   layout:Em.Handlebars.compile('<i class="fa fa-fw fa-lg fa-warning"></i>'),
   tagName:'span',
   tooltip:'Warning',
+  placement:'bottom',
   initTooltip: function(){
-    var tipMsg = this.get('tooltip');
+    var tipMsg = this.get('tooltip'),
+    postion = this.get('placement');
     this.$().tooltip({
       title:tipMsg,
-      placement:'bottom'
+      placement:postion
     });
   }.on('didInsertElement'),
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueHierarchy.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueHierarchy.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueHierarchy.js
index 64a28343..674c9c7 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueHierarchy.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueHierarchy.js
@@ -29,6 +29,17 @@
        .filterBy('parentPath', this.get('parent'));
    }.property('depth', 'parent', 'queues.length', 'queues.@each.name'),
 
+   cildrenQueues: function() {
+     var leafQs = this.get('leafQs'),
+      deltedQs = this.get('deletedQs');
+
+     var deletedAtDepth = deltedQs
+      .filterBy('depth', this.get('depth'))
+      .filterBy('parentPath', this.get('parent'));
+
+     return leafQs.pushObjects(deletedAtDepth);
+   }.property('leafQs.length', 'deletedQs.[]'),
+
    childDepth: function () {
      return this.get('leafQs.firstObject.depth') + 1;
    }.property('depth'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueMapping.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueMapping.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueMapping.js
index 107b377..1d07351 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueMapping.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueMapping.js
@@ -34,6 +34,7 @@
    selectedLeafQueueNameForUsers: null,
    selectedLeafQueueNameForGroups: null,
    isQueueMappingsDirty: false,
+   scheduler: null,
 
    actions: {
      showMappingOptions: function(){
@@ -51,6 +52,13 @@
      },
      toggleMappingOverride: function() {
        this.toggleProperty('mappingsOverrideEnable');
+     },
+     rollbackProp: function(prop, item) {
+       if (prop === "queue_mappings") {
+         var oldMappings = (item.changedAttributes()[prop][0])? item.changedAttributes()[prop][0].split(',') : [];
+         this.set('queueMappings', oldMappings);
+       }
+       this.sendAction("rollbackProp", prop, item);
      }
    },
 
@@ -103,9 +111,10 @@
 
    addCustomQueueMappings: function(csValues, selectedLeafQName){
      var that = this;
-     csValues = csValues.trim() || '',
-     userOrGroupNames = csValues.split(',') || [],
-     mappingPattern = this.get('selectedMapping');
+       csValues = csValues.trim() || '',
+       userOrGroupNames = csValues.split(',') || [],
+       mappingPattern = this.get('selectedMapping');
+
      userOrGroupNames.forEach(function(ugname){
        that.get('queueMappings').pushObject(mappingPattern.replace('%name', ugname).replace('%qname', selectedLeafQName));
      });
@@ -143,5 +152,13 @@
 
    destroyEventListeners: function() {
      this.$('#collapseQueueMappingsBtn').off('click');
-   }.on('willDestroyElement')
+   }.on('willDestroyElement'),
+
+   isMappingsDirty: function() {
+     return this.get('scheduler').changedAttributes().hasOwnProperty('queue_mappings');
+   }.property('scheduler.queue_mappings'),
+
+   isOverrideEnableDirty: function() {
+     return this.get('scheduler').changedAttributes().hasOwnProperty('queue_mappings_override_enable');
+   }.property('scheduler.queue_mappings_override_enable')
  });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueSummary.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueSummary.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueSummary.js
index 2690c40..8923e8e 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueSummary.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/queueSummary.js
@@ -31,7 +31,7 @@
 
    isQueueStateNeedRefresh: function() {
      var qsNeedRefresh = this.get('queuesNeedRefresh'),
-      qq = this.get('queue');
+       qq = this.get('queue');
 
      if (qsNeedRefresh && qsNeedRefresh.findBy('path', qq.get('path'))) {
        return true;
@@ -44,7 +44,7 @@
 
    isQueueCapacityNeedRefresh: function() {
      var qsNeedRefresh = this.get('queuesNeedRefresh'),
-      qq = this.get('queue');
+       qq = this.get('queue');
 
      if (qsNeedRefresh && qsNeedRefresh.findBy('path', qq.get('path'))) {
        return true;
@@ -89,22 +89,5 @@
 
    isNewQueue: function() {
      return this.get('queue.isNewQueue');
-   }.property('queue.isNewQueue'),
-
-   effectiveCapacity: function() {
-     var currentQ = this.get('queue'),
-       allQueues = this.get('allQueues'),
-       effectiveCapacityRatio = 1;
-
-     while (currentQ !== null) {
-       effectiveCapacityRatio *= (currentQ.get('capacity') / 100);
-       currentQ = allQueues.findBy('id', currentQ.get('parentPath').toLowerCase()) || null;
-     }
-
-     var effectiveCapacityPercent = effectiveCapacityRatio * 100,
-       absoluteCapacity = parseFloat(parseFloat(effectiveCapacityPercent).toFixed(this.get('precision')));
-       this.get('queue').set('absolute_capacity', absoluteCapacity || 0);
-
-     return absoluteCapacity;
-   }.property('queue.capacity', 'allQueues.@each.capacity', 'allQueues.length')
+   }.property('queue.isNewQueue')
  });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/sunburstChart.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/sunburstChart.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/sunburstChart.js
new file mode 100644
index 0000000..d5b19ae
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/sunburstChart.js
@@ -0,0 +1,339 @@
+/**
+ * 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');
+
+function _getSunburstChartDataForDefault(queue, json, allQueues) {
+  var childrenQs = allQueues.filterBy('parentPath', queue.get('path')),
+    qdata = {
+      "name": queue.get('name'),
+      "path": queue.get('path'),
+      "capacity": queue.get('capacity'),
+      "absoluteCapacity": queue.get('absolute_capacity')||0,
+      "size": queue.get('capacity'),
+      "isLabel": false
+    };
+
+  if (!Ember.isEmpty(childrenQs)) {
+    qdata["children"] = [];
+  }
+
+  if (json["children"]) {
+    json["children"].push(qdata);
+  }
+
+  childrenQs.forEach(function(child) {
+    return _getSunburstChartDataForDefault(child, qdata, allQueues);
+  });
+  return json;
+}
+
+function _getSunburstChartDataForLabel(queue, json, allQueues, labelName) {
+  var childrenQs = allQueues.filterBy('parentPath', queue.get('path')),
+    qLabel = queue.get('labels').findBy('name', labelName),
+    qdata = {
+      "name": queue.get('name'),
+      "path": queue.get('path'),
+      "capacity": qLabel?qLabel.get('capacity') : 0,
+      "absoluteCapacity": 0,
+      "size": qLabel? qLabel.get('capacity') : 0,
+      "isLabel": true
+    };
+
+  if (!Ember.isEmpty(childrenQs)) {
+    qdata["children"] = [];
+  }
+
+  if (json["children"]) {
+    json["children"].push(qdata);
+  }
+
+  childrenQs.forEach(function(child) {
+    return _getSunburstChartDataForLabel(child, qdata, allQueues, labelName);
+  });
+  return json;
+}
+
+App.SunburstChartComponent = Ember.Component.extend({
+  layoutName: 'components/sunburstChart',
+  queues: null,
+  selectedQueue: null,
+  allNodeLabels: null,
+
+  width: 0,
+  height: 0,
+  radius: 0,
+  data: null,
+  colorScale: null,
+  chartRendered: false,
+  queueCapacityTypeSelected: null,
+
+  queueCapacityTypeValues: null,
+
+  didInsertElement: function() {
+    this.initializeChart();
+    this.initializeCapacityTypeOptions();
+    this.set("queueCapacityTypeSelected", null);
+    this.setChartDataForDefault();
+    this.renderChart();
+  },
+
+  initializeChart: function() {
+    var width = this.$().width();
+    this.$('.panel-default').height(width);
+    var height = this.$('.panel-default').height() - this.$('#top_container').outerHeight();
+
+    var vizWidth = width - 60;
+    var vizHeight = height - 80;
+    var radius = Math.min(vizWidth, vizHeight) / 2;
+
+    this.set('width', vizWidth);
+    this.set('height', vizHeight);
+    this.set('radius', radius);
+    this.set('colorScale', d3.scale.category20());
+  },
+
+  initializeCapacityTypeOptions: function() {
+    var options = [{
+      name: "Default",
+      value: null
+    }];
+    if (this.get('allNodeLabels') !== null) {
+      this.get('allNodeLabels').forEach(function(label) {
+        options.push({
+          name: "Label: " + label.name,
+          value: label.name
+        });
+      });
+    }
+    this.set("queueCapacityTypeValues", options);
+  },
+
+  setChartDataForDefault: function() {
+    var queues = this.get('queues'),
+      rootQ = queues.findBy('name', 'root'),
+      dataJson = {
+        "name": "sunburst",
+        "children": []
+      };
+
+    var data = _getSunburstChartDataForDefault(rootQ, dataJson, queues);
+    this.set("data", data);
+  },
+
+  setChartDataForLabel: function() {
+    var queues = this.get('queues'),
+      allNodeLabels = this.get('allNodeLabels'),
+      rootQ = queues.findBy('name', 'root'),
+      labelName = this.get('queueCapacityTypeSelected');
+
+    var dataJson = {
+      "name": "sunburst",
+      "children": []
+    };
+    var data = _getSunburstChartDataForLabel(rootQ, dataJson, queues, labelName);
+    this.set("data", data);
+  },
+
+  renderChart: function() {
+    var self = this,
+      width = this.get('width'),
+      height = this.get('height'),
+      radius = this.get('radius'),
+      data = this.get('data'),
+      colors = this.get('colorScale');
+
+    var vis = d3.select("#sunburst_chart").append("svg:svg")
+      .attr("width", width)
+      .attr("height", height)
+      .append("svg:g")
+      .attr("id", "sunburst_container")
+      .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
+
+    var partition = d3.layout.partition()
+      .size([2 * Math.PI, radius * radius])
+      .value(function(d) {
+        return d.size;
+      });
+
+    var arc = d3.svg.arc()
+      .startAngle(function(d) { return d.x; })
+      .endAngle(function(d) { return d.x + d.dx; })
+      .innerRadius(function(d) { return Math.sqrt(d.y); })
+      .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
+
+    vis.append("svg:circle")
+      .attr("r", radius)
+      .style("opacity", 0);
+
+    var nodes = partition.nodes(data)
+      .filter(function(d) {
+         return (d.dx > 0.005);
+      });
+
+    var path = vis.data([data]).selectAll("path")
+      .data(nodes)
+      .enter().append("svg:path")
+      .attr("id", function(d) { return d.path; })
+      .attr("data-node", function(d) {
+        var node = {
+          name: d.name,
+          path: d.path,
+          capacity: d.capacity,
+          absoluteCapacity: d.absoluteCapacity,
+          isLabel: d.isLabel
+        };
+        return JSON.stringify(node);
+      })
+      .attr("display", function(d) { return d.depth ? null : "none"; })
+      .attr("d", arc)
+      .attr("fill-rule", "evenodd")
+      .style("fill", function(d) {
+        var colr = colors(d.name);
+        d.color = colr;
+        return colr;
+      })
+      .style("opacity", 1);
+
+    this.set('chartRendered', true);
+    this.adjustPositions();
+  },
+
+  mouseover: function(d, elem) {
+    this.showQueueInfo(d);
+    d3.selectAll("path").style("opacity", 0.3);
+    d3.select(elem).style("opacity", 1);
+  },
+
+  showQueueInfo: function(node) {
+    var precentage = node.isLabel? node.capacity : node.absoluteCapacity;
+    var percentageString = precentage + "%";
+    d3.select("#capacityPercentage").text(percentageString);
+    d3.select("#queuePath").text(node.path);
+    if (node.isLabel) {
+      d3.select("#type_text").text("Capacity:");
+    } else {
+      d3.select("#type_text").text("Abs Cap:");
+    }
+    d3.select("#explanation").style("visibility", "");
+    d3.select("#queue_info").style("visibility", "");
+  },
+
+  hideQueueInfo: function() {
+    d3.select("#queuePath").text("");
+    d3.select("#type_text").text("");
+    d3.select("#capacityPercentage").text("");
+    d3.select("#explanation").style("visibility", "hidden");
+    d3.select("#queue_info").style("visibility", "hidden");
+  },
+
+  mouseleave: function(d) {
+    d3.selectAll("path").style("opacity", 1);
+    d3.select("#explanation").style("visibility", "hidden");
+    d3.select("#queue_info").style("visibility", "hidden");
+    var queue = this.get("selectedQueue");
+    if (queue) {
+      var node = this.$("path[id='"+queue.get('path')+"']").data('node');
+      this.showQueueInfo({
+        name: node.name,
+        path: node.path,
+        capacity: node.capacity,
+        absoluteCapacity: node.absoluteCapacity,
+        isLabel: node.isLabel
+      });
+    }
+  },
+
+  hightlightSelectedQueue: function() {
+    this.removeHighlightFromChart();
+    var width = this.get('width'),
+    height = this.get('height'),
+    queue = this.get("selectedQueue");
+    if (queue) {
+      d3.selectAll("path").style("opacity", 0.3);
+      d3.select("path[id='"+queue.get('path')+"']")
+        .style("fill", "#3276b1")
+        .style("opacity", 1);
+      var node = this.$("path[id='"+queue.get('path')+"']").data('node');
+      this.showQueueInfo({
+        name: node.name,
+        path: node.path,
+        capacity: node.capacity,
+        absoluteCapacity: node.absoluteCapacity,
+        isLabel: node.isLabel
+      });
+    }
+  },
+
+  removeHighlightFromChart: function() {
+    d3.selectAll("path").style("opacity", 1);
+    d3.selectAll("path").each(function(node) {
+      if (node.path) {
+        d3.select("path[id='"+node.path+"']")
+          .style("fill", node.color);
+      }
+    });
+    this.hideQueueInfo();
+  },
+
+  adjustPositions: function() {
+    var rootOffset = this.$("path[id='root']").offset(),
+    rootPathDims = this.$("path[id='root']")[0].getBoundingClientRect(),
+    rootW = rootPathDims.width,
+    rootH = rootPathDims.height,
+    explanationH = this.$("#explanation").height(),
+    explanationW = this.$("#explanation").width();
+
+    var rootCenterX = rootOffset.left + rootW / 2,
+    rootCenterY = rootOffset.top + rootH / 2,
+    posX = rootCenterX - explanationW / 2,
+    posY = rootCenterY - explanationH / 2;
+
+    this.$("#explanation").offset({left: posX, top: posY});
+  },
+
+  renderObserver: function() {
+    d3.select("#sunburst_chart svg").remove();
+    this.set('chartRendered', false);
+    this.set("queueCapacityTypeSelected", null);
+    this.setChartDataForDefault();
+    this.renderChart();
+    this.hightlightSelectedQueue();
+  }.observes('queues', 'queues.[]', 'queues.@each.capacity'),
+
+  queueSelectionObserver: function() {
+    if (this.get('selectedQueue') && this.get('chartRendered')) {
+      this.hightlightSelectedQueue();
+    } else {
+      this.removeHighlightFromChart();
+    }
+  }.observes('selectedQueue', 'chartRendered'),
+
+  watchTypeSelection: function() {
+    d3.select("#sunburst_chart svg").remove();
+    this.set('chartRendered', false);
+    if (this.get("queueCapacityTypeSelected") !== null) {
+      this.setChartDataForLabel();
+    } else {
+      this.setChartDataForDefault();
+    }
+    this.renderChart();
+    this.hightlightSelectedQueue();
+  }.observes("queueCapacityTypeSelected")
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/xmldiffViewer.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/xmldiffViewer.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/xmldiffViewer.js
new file mode 100644
index 0000000..62431f6
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/xmldiffViewer.js
@@ -0,0 +1,101 @@
+/**
+ * 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.XmldiffViewerComponent = Ember.Component.extend({
+  layoutName: 'components/xmldiffViewer',
+  diffConfig: null,
+  viewConfig: null,
+
+  actions: {
+    closeDiffViewer: function() {
+      this.set('diffConfig', null);
+      this.set('viewConfig', null);
+    }
+  },
+
+  diffViewObserver: function() {
+    if (this.get('diffConfig')) {
+      this.showXmlDiffView();
+    }
+  }.observes('diffConfig'),
+
+  viewConfigObserver: function() {
+    if (this.get('viewConfig')) {
+      this.showCapSchedViewXml();
+    }
+  }.observes('viewConfig'),
+
+  showXmlDiffView: function() {
+    this.$("#xmldiffViewerDialog").modal('show');
+    var config = this.get('diffConfig'),
+      basetxt = difflib.stringAsLines(config.baseXML);
+      newtxt = difflib.stringAsLines(config.newXML),
+      sm = new difflib.SequenceMatcher(basetxt, newtxt),
+      opcodes = sm.get_opcodes(),
+      $diffOutput = this.$('#xmldiffOutput');
+
+    this.showHideOutputContainers('diffView');
+    this.setDialogDimentions();
+
+    $diffOutput.append(diffview.buildView({
+      baseTextLines: basetxt,
+      newTextLines: newtxt,
+      opcodes: opcodes,
+      baseTextName: 'Base XML',
+      newTextName: 'New XML',
+      contextSize: 2,
+      viewType: 0
+    }));
+  },
+
+  showCapSchedViewXml: function() {
+    this.$("#xmldiffViewerDialog").modal('show');
+    var config = this.get('viewConfig'),
+      $output = this.$('#capshedViewXml');
+
+    this.showHideOutputContainers('xmlView');
+    this.setDialogDimentions(true);
+    $output.text(config.xmlConfig);
+  },
+
+  showHideOutputContainers: function(viewType) {
+    this.$('#xmldiffOutput').empty().hide();
+    this.$('#capshedViewXml').empty().hide();
+    if (viewType === 'diffView') {
+      this.$('#xmldiffOutput').show();
+    } else {
+      this.$('#capshedViewXml').show();
+    }
+  },
+
+  setDialogDimentions: function(hideOverflow) {
+    var dialogHt = this.$("#xmldiffViewerDialog").height(),
+      contentHt = dialogHt-60,
+      bodyHt = contentHt-170;
+
+    this.$("#xmldiffViewerDialog").find('.modal-content').height(contentHt);
+    this.$("#xmldiffViewerDialog").find('.modal-body').height(bodyHt);
+    if (hideOverflow) {
+      this.$("#xmldiffViewerDialog").find('.modal-body').css('overflow', 'hidden');
+    } else {
+      this.$("#xmldiffViewerDialog").find('.modal-body').css('overflow', 'auto');
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/advanced.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/advanced.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/advanced.js
index c079079..af15fa5 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/advanced.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/advanced.js
@@ -25,6 +25,7 @@ App.CapschedAdvancedController = Ember.Controller.extend({
 
   actions: {
     rollbackQueueMappingProps: function() {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
       var sched = this.get('scheduler'),
       attributes = sched.changedAttributes(),
       props = this.queueMappingProps;
@@ -33,6 +34,16 @@ App.CapschedAdvancedController = Ember.Controller.extend({
           sched.set(prop, attributes[prop][0]);
         }
       });
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+    },
+    rollbackProp: function(prop, item) {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
+      var attributes = item.changedAttributes();
+      if (attributes.hasOwnProperty(prop)) {
+        item.set(prop, attributes[prop][0]);
+      }
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+      this.afterRollbackProp();
     },
     showSaveConfigDialog: function(mode) {
       if (mode) {
@@ -76,5 +87,13 @@ App.CapschedAdvancedController = Ember.Controller.extend({
 
   forceRefreshRequired: function() {
     return !this.get('isQueueMappingsDirty') && this.get('isRefreshOrRestartNeeded');
-  }.property('isQueueMappingsDirty', 'isRefreshOrRestartNeeded')
+  }.property('isQueueMappingsDirty', 'isRefreshOrRestartNeeded'),
+
+  afterRollbackProp: function() {
+    if (this.get('isQueueMappingsDirty')) {
+      this.set('isRefreshOrRestartNeeded', true);
+    } else {
+      this.set('isRefreshOrRestartNeeded', false);
+    }
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/capsched.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/capsched.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/capsched.js
index 447cae0..631edbb 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/capsched.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/capsched.js
@@ -19,6 +19,11 @@
 var App = require('app');
 
 App.CapschedController = Ember.Controller.extend({
+  queues: null,
+  precision: 2,
+  selectedQueue: null,
+  allNodeLabels: Ember.computed.alias('store.nodeLabels.content'),
+
   actions: {
     loadTagged: function (tag) {
       this.transitionToRoute('capsched.scheduler').then(function() {
@@ -27,7 +32,7 @@ App.CapschedController = Ember.Controller.extend({
     },
     clearAlert: function () {
       this.set('alertMessage',null);
-    },
+    }
   },
 
   /**
@@ -42,6 +47,26 @@ App.CapschedController = Ember.Controller.extend({
    */
   isNotOperator: Ember.computed.not('isOperator'),
 
+  queuesWatcher: function() {
+    var allQueues = this.get('queues') || [];
+    allQueues.forEach(function(queue) {
+      var absCap = this.getAbsoluteCapacityForQueue(queue);
+      queue.set('absolute_capacity', absCap);
+    }.bind(this));
+  }.observes('queues', 'queues.[]', 'queues.@each.capacity').on('init'),
+
+  getAbsoluteCapacityForQueue: function(queue) {
+    var allQueues = this.get('queues');
+    var effectCapRatio = 1;
+    while (queue !== null) {
+      effectCapRatio *= queue.get('capacity') / 100;
+      queue = allQueues.findBy('id', queue.get('parentPath').toLowerCase()) || null;
+    }
+    var effectCapPercent = effectCapRatio * 100,
+    absoluteCap = parseFloat(parseFloat(effectCapPercent).toFixed(this.get('precision')));;
+    return absoluteCap;
+  },
+
   alertMessage: null,
 
   tags: function () {
@@ -60,5 +85,17 @@ App.CapschedController = Ember.Controller.extend({
 
   stopSpinner: function() {
     this.set('showSpinner', false);
+  },
+
+  diffXmlConfig: null,
+
+  viewConfigXmlDiff: function(config) {
+    this.set('diffXmlConfig', config);
+  },
+
+  viewXmlConfig: null,
+
+  viewCapSchedXml: function(config) {
+    this.set('viewXmlConfig', config);
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/editqueue.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/editqueue.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/editqueue.js
index 7c62ef0..9d84704 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/editqueue.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/editqueue.js
@@ -66,16 +66,19 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
     editQueueName: function() {
       this.set('enableEditQName', true);
       this.set('updatedQName', this.get('content.name'));
+      this.set('controllers.capschedQueuesconf.isEditingQueueName', true);
     },
     cancelQNameEdit: function() {
       this.set('enableEditQName', false);
       this.set('isInvalidQName', false);
       this.set('invalidQNameMessage', '');
+      this.set('controllers.capschedQueuesconf.isEditingQueueName', false);
     },
     renameQueue: function() {
       if (this.validateQName()) {
         return;
       }
+      this.set('controllers.capschedQueuesconf.isEditingQueueName', false);
       this.set('content.name', this.get('updatedQName'));
       this.set('enableEditQName', false);
     },
@@ -83,6 +86,24 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
       this.send('rollbackProp', 'disable_preemption', this.get('content'));
       this.send('rollbackProp', 'isPreemptionInherited', this.get('content'));
       this.set('content.isPreemptionOverriden', false);
+    },
+    rollbackProp: function(prop, item) {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
+      var attributes = item.changedAttributes();
+      if (attributes.hasOwnProperty(prop)) {
+        item.set(prop, attributes[prop][0]);
+      }
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+      this.afterRollbackProp();
+    }
+  },
+
+  afterRollbackProp: function() {
+    var isAnyQDirty = this.get('allQueues').isAny('isAnyDirty', true);
+    if (isAnyQDirty) {
+      this.set('isRefreshOrRestartNeeded', true);
+    } else {
+      this.set('isRefreshOrRestartNeeded', false);
     }
   },
 
@@ -114,6 +135,15 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
     this.validateQName();
   }.observes('updatedQName', 'updatedQName.length'),
 
+  absoluteClusterCapacity: function() {
+    return this.get('content.absolute_capacity');
+  }.property('content', 'content.absolute_capacity'),
+
+  absoluteClusterBarWidth: function() {
+    var absCap = this.get('absoluteClusterCapacity');
+    return this.get('widthPattern').fmt(absCap);
+  }.property('absoluteClusterCapacity'),
+
   /**
    * Collection of modified fields in queue.
    * @type {Object} - { [fileldName] : {Boolean} }
@@ -250,9 +280,10 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
    },
 
    isAnyQueueResourcesDirty: function() {
-     return this.get('queueDirtyFields.user_limit_factor') || this.get('queueDirtyFields.minimum_user_limit_percent')
-      || this.get('queueDirtyFields.maximum_applications') || this.get('queueDirtyFields.maximum_am_resource_percent')
-      || this.get('queueDirtyFields.ordering_policy') || this.get('queueDirtyFields.enable_size_based_weight');
+     var changedAttrs = this.get('content').changedAttributes();
+     return changedAttrs.hasOwnProperty('user_limit_factor') || changedAttrs.hasOwnProperty('minimum_user_limit_percent')
+      || changedAttrs.hasOwnProperty('maximum_applications') || changedAttrs.hasOwnProperty('maximum_am_resource_percent')
+      || changedAttrs.hasOwnProperty('ordering_policy') || changedAttrs.hasOwnProperty('enable_size_based_weight');
    }.property(
      'content.user_limit_factor',
      'content.minimum_user_limit_percent',
@@ -382,7 +413,8 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
     },
 
     isAnyAccessControlListDirty: function() {
-      return this.get('queueDirtyFields.acl_administer_queue') || this.get('queueDirtyFields.acl_submit_applications');
+      var chagedAttrs = this.get('content').changedAttributes();
+      return chagedAttrs.hasOwnProperty('acl_administer_queue') || chagedAttrs.hasOwnProperty('acl_submit_applications');
     }.property('content.acl_submit_applications', 'content.acl_administer_queue'),
 
     /**
@@ -443,8 +475,9 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
       if (this.get('isLeafQ')) {
         return false;
       }
-      return this.get('queueDirtyFields.queues') || this.get('childrenQueues').anyBy('isDirtyCapacity', true) || this.get('childrenQueues').anyBy('isDirtyMaxCapacity', true);
-    }.property('content', 'content.queues', 'childrenQueues.@each.isDirtyCapacity', 'childrenQueues.@each.isDirtyMaxCapacity'),
+      return this.get('queueDirtyFields.queues') || this.get('childrenQueues').anyBy('isDirtyCapacity', true)
+        || this.get('childrenQueues').anyBy('isDirtyMaxCapacity', true) || this.get('warnInvalidCapacity');
+    }.property('content', 'content.queues', 'childrenQueues.@each.isDirtyCapacity', 'childrenQueues.@each.isDirtyMaxCapacity', 'warnInvalidCapacity'),
 
    /**
     * Adds observers for each queue attribute.
@@ -598,12 +631,14 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
    warnInvalidTotalLabelCapacity: false,
 
    isAnyChildrenQueueLabelDirty: function() {
-     if (this.get('isLeafQ')) {
-       return this.get('queueDirtyFields.default_node_label_expression') || false;
+     var changedAttrs = this.get('content').changedAttributes();
+     if (this.get('content.queues') === null) {
+       return changedAttrs.hasOwnProperty('default_node_label_expression');
      }
-     return this.get('childrenQueues').anyBy('isLabelsDirty', true) || this.get('queueDirtyFields.default_node_label_expression')
-      || this.get('childrenLabelsForQueue').anyBy('isDirtyLabelCapacity', true) || this.get('childrenLabelsForQueue').anyBy('isDirtyLabelMaxCapacity', true);
-   }.property('content', 'childrenQueues.@each.isLabelsDirty', 'childrenLabelsForQueue.@each.isDirtyLabelCapacity', 'childrenLabelsForQueue.@each.isDirtyLabelMaxCapacity', 'content.default_node_label_expression'),
+     return this.get('childrenQueues').anyBy('isLabelsDirty', true) || changedAttrs.hasOwnProperty('default_node_label_expression')
+      || this.get('childrenLabelsForQueue').anyBy('isDirtyLabelCapacity', true) || this.get('childrenLabelsForQueue').anyBy('isDirtyLabelMaxCapacity', true)
+      || this.get('warnInvalidTotalLabelCapacity');
+   }.property('content', 'childrenQueues.@each.isLabelsDirty', 'childrenLabelsForQueue.@each.isDirtyLabelCapacity', 'childrenLabelsForQueue.@each.isDirtyLabelMaxCapacity', 'content.default_node_label_expression', 'warnInvalidTotalLabelCapacity'),
 
    //Preemption
    isPreemptionSupported: Ember.computed.alias('store.isPreemptionSupported'),
@@ -644,7 +679,7 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
    },
 
    isQueuePreemptionDirty: function() {
-     return this.get('queueDirtyFields.disable_preemption');
+     return this.get('content').changedAttributes().hasOwnProperty('disable_preemption');
    }.property('content.disable_preemption', 'content.isPreemptionInherited'),
 
    doOverridePreemption: function(key, value) {
@@ -667,10 +702,5 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
        this.set('content.isPreemptionInherited', true);
        this.set('content.disable_preemption', '');
      }
-   }.observes('content.isPreemptionOverriden'),
-
-   saveRefreshRestartWatcher: function() {
-     this.set('isRefreshOrRestartNeeded', this.get('isAnyQueueResourcesDirty') || this.get('isAnyAccessControlListDirty')
-      || this.get('isAnyChildrenQueueCapacityDirty') || this.get('isAnyChildrenQueueLabelDirty') || this.get('isQueuePreemptionDirty'));
-   }.observes('isAnyQueueResourcesDirty', 'isAnyAccessControlListDirty', 'isAnyChildrenQueueCapacityDirty', 'isAnyChildrenQueueLabelDirty', 'isQueuePreemptionDirty')
+   }.observes('content.isPreemptionOverriden')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queuesconf.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queuesconf.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queuesconf.js
index 6a6717a..e7fba41 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queuesconf.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/queuesconf.js
@@ -32,16 +32,19 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
   allNodeLabelRecords: [],
   queuesNeedRefresh: Ember.computed.alias('store.queuesNeedRefresh'),
   isRefreshOrRestartNeeded: false,
+  deletedQueues: Ember.computed.alias('store.deletedQueues'),
 
   actions: {
     addNewQueue: function() {
       this.set('newQueueName', '');
       this.set('showQueueNameInput', true);
+      this.set('isCreatingNewQueue', true);
     },
     createNewQueue: function() {
       if (this.validateQueueName()) {
         return;
       }
+      this.set('isCreatingNewQueue', false);
       var store = this.get('store'),
       queueName = this.get('newQueueName'),
       parentPath = this.get('selectedQueue.path'),
@@ -61,6 +64,7 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
         freeLeafCapacity = (totalLeafCapacity < 100) ? 100 - totalLeafCapacity : 0;
       }
       var qCapacity = (newInLeaf) ? 100 : freeLeafCapacity;
+      var requireRestart = (this.get('selectedQueue.isLeafQ') && !this.get('selectedQueue.isNewQueue'))? true : false;
       newQueue = store.createRecord('queue', {
         id: queuePath.toLowerCase(),
         name: queueName,
@@ -69,7 +73,8 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
         depth: depth,
         isNewQueue: true,
         capacity: qCapacity,
-        maximum_capacity: 100
+        maximum_capacity: 100,
+        requireRestart: requireRestart
       });
       this.set('newQueue', newQueue);
       store.saveAndUpdateQueue(newQueue).then(Em.run.bind(this, 'saveAndUpdateQueueSuccess', newQueue));
@@ -86,8 +91,11 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
       this.set('showQueueNameInput', false);
       this.set('isInvalidQueueName', false);
       this.set('invalidQueueNameMessage', '');
+      this.set('isCreatingNewQueue', false);
     },
     discardQueuesChanges: function() {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
+      var tempRestart = this.get('isQueuesMustNeedRestart');
       var allQueues = this.get('queues');
       allQueues.forEach(function(qq){
         var qAttrs = qq.changedAttributes();
@@ -105,12 +113,13 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
             }
           }
         });
-        //Setting root label capacities back to 100,
-        //if discard changes set root label capacity to 0.
+        //Setting root label capacities back to 100, if discard changes set root label capacity to 0.
         if (qq.get('id') === 'root') {
           qq.get('labels').setEach('capacity', 100);
         }
       });
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+      this.set('isQueuesMustNeedRestart', tempRestart);
     },
     stopQueue: function() {
       this.set('selectedQueue.state', _stopState);
@@ -139,6 +148,17 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     },
     showConfirmDialog: function() {
       this.set('isConfirmDialogOpen', true);
+    },
+    saveCapSchedConfigs: function() {
+      if (this.get('saveMode') === '') {
+        var holder = {
+          refresh: this.get('isRefreshOrRestartNeeded')
+        };
+        this.set('tempRefreshHolder', holder);
+      } else {
+        this.set('tempRefreshHolder', null);
+      }
+      return true;
     }
   },
 
@@ -146,11 +166,48 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     return this.get('queues').isAny('isAnyDirty', true);
   }.property('queues.@each.isAnyDirty'),
 
-  isQueuesNeedRefreshOrRestart: Ember.computed.or('isAnyQueueDirty', 'needRefresh', 'needRestart', 'isRefreshOrRestartNeeded'),
+  isQueuesNeedRefreshOrRestart: function() {
+    var isNeed = this.get('isAnyQueueDirty') || this.get('needRefresh')
+      || this.get('queuesRequireRestart') || this.get('isRefreshOrRestartNeeded');
+    return isNeed;
+  }.property('isAnyQueueDirty', 'needRefresh', 'queuesRequireRestart', 'isRefreshOrRestartNeeded', 'canNotSave'),
+
+  isQueuesMustNeedRestart: false,
 
   forceRefreshOrRestartRequired: function() {
-    return !this.get('isAnyQueueDirty') && this.get('isRefreshOrRestartNeeded');
-  }.property('isAnyQueueDirty', 'isRefreshOrRestartNeeded'),
+    return !this.get('isAnyQueueDirty') && (this.get('isRefreshOrRestartNeeded') || this.get('isQueuesMustNeedRestart'));
+  }.property('isAnyQueueDirty', 'isRefreshOrRestartNeeded', 'isQueuesMustNeedRestart'),
+
+  refreshRestartWatcher: function() {
+    if (this.get('tempRefreshHolder')) {
+      var holder = this.get('tempRefreshHolder');
+      this.set('isRefreshOrRestartNeeded', holder.refresh||false);
+      this.set('tempRefreshHolder', null);
+    }
+  }.observes('isRefreshOrRestartNeeded'),
+
+  isDirtyQueuesNeedRefreshQsOp: function() {
+    if (this.get('isAnyQueueDirty') || this.get('needRefresh') || this.get('isRefreshOrRestartNeeded')) {
+      if (this.get('queuesRequireRestart')) {
+        return false;
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }.property('isAnyQueueDirty', 'needRefresh', 'queuesRequireRestart', 'isRefreshOrRestartNeeded', 'canNotSave'),
+
+  isDirtyQueuesNeedRestartRmOp: function() {
+    if (this.get('queuesRequireRestart') || this.get('isQueuesMustNeedRestart')) {
+      return true;
+    } else {
+      return false;
+    }
+  }.property('isAnyQueueDirty', 'queuesRequireRestart', 'isQueuesMustNeedRestart', 'canNotSave'),
+
+  showNeedRefreshOrRestartWarning: function() {
+    return this.get('isQueuesNeedRefreshOrRestart') && !this.get('canNotSave');
+  }.property('isQueuesNeedRefreshOrRestart', 'canNotSave'),
 
   selectedQueue: null,
   newQueue: null,
@@ -159,6 +216,13 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
   isInvalidQueueName: false,
   invalidQueueNameMessage: '',
 
+  isCreatingNewQueue: false,
+  isEditingQueueName: false,
+
+  isCreaingOrRenamingQueue: function() {
+    return this.get('isCreatingNewQueue')||this.get('isEditingQueueName');
+  }.property('isCreatingNewQueue', 'isEditingQueueName'),
+
   validateQueueName: function() {
     var parentPath = this.get('selectedQueue.path'),
     queueName = this.get('newQueueName'),
@@ -289,6 +353,34 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     }.bind(this));
   }.observes('queues.length','queues.@each.capacity'),
 
+  newQueuesNeedRestart: function() {
+    return this.get('queues')
+      .filterBy('isNewQueue', true)
+      .filterBy('requireRestart', true);
+  }.property('queues.length', 'queues.@each.isNewQueue', 'queues.@each.requireRestart'),
+
+  hasNewQueuesNeedRestart: Ember.computed.notEmpty('newQueuesNeedRestart.[]'),
+
+  queuesRequireRestart: Ember.computed.or('needRestart', 'hasNewQueuesNeedRestart', 'isQueuesMustNeedRestart'),
+
+  disableRefreshBtn: function() {
+    var disable = this.get('canNotSave') || this.get('queuesRequireRestart');
+    return disable;
+  }.property('canNotSave', 'queuesRequireRestart', 'isAnyQueueDirty'),
+
+  restartWatcher: function() {
+    var restart = this.get('needRestart') || this.get('hasNewQueuesNeedRestart');
+    this.set('isQueuesMustNeedRestart', restart);
+  }.observes('needRestart', 'hasNewQueuesNeedRestart'),
+
+  dirtyQueueWatcher: function() {
+    if (this.get('isAnyQueueDirty')) {
+      this.set('isRefreshOrRestartNeeded', true);
+    } else {
+      this.set('isRefreshOrRestartNeeded', false);
+    }
+  }.observes('isAnyQueueDirty'),
+
   /**
    * True if newQueue is not empty.
    * @type {Boolean}
@@ -347,7 +439,7 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
    * check if RM needs restart
    * @type {bool}
    */
-  needRestart: Em.computed.and('hasDeletedQueues', 'isOperator'),
+  needRestart: Ember.computed.and('hasDeletedQueues', 'isOperator'),
 
   /**
    * check there is some changes for save

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/scheduler.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/scheduler.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/scheduler.js
index 40e3e24..aa139b1 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/scheduler.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/controllers/scheduler.js
@@ -28,6 +28,7 @@ App.CapschedSchedulerController = Ember.Controller.extend({
 
   actions: {
     rollbackSchedulerProps: function() {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
       var sched = this.get('scheduler'),
       attributes = sched.changedAttributes(),
       props = this.schedulerProps;
@@ -36,6 +37,16 @@ App.CapschedSchedulerController = Ember.Controller.extend({
           sched.set(prop, attributes[prop][0]);
         }
       });
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+    },
+    rollbackProp: function(prop, item) {
+      var tempRefreshNeeded = this.get('isRefreshOrRestartNeeded');
+      var attributes = item.changedAttributes();
+      if (attributes.hasOwnProperty(prop)) {
+        item.set(prop, attributes[prop][0]);
+      }
+      this.set('isRefreshOrRestartNeeded', tempRefreshNeeded);
+      this.afterRollbackProp();
     },
     showConfirmDialog: function() {
       this.set('isConfirmDialogOpen', true);
@@ -102,5 +113,13 @@ App.CapschedSchedulerController = Ember.Controller.extend({
   }, {
     label: 'Dominant Resource Calculator',
     value: 'org.apache.hadoop.yarn.util.resource.DominantResourceCalculator'
-  }]
+  }],
+
+  afterRollbackProp: function() {
+    if (this.get('isSchedulerDirty')) {
+      this.set('isRefreshOrRestartNeeded', true);
+    } else {
+      this.set('isRefreshOrRestartNeeded', false);
+    }
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js
index 0f68a10..e2d67bd 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/models/queue.js
@@ -36,7 +36,6 @@ App.Label = DS.Model.extend({
   isDefault: function () {
     return this.get('queue.default_node_label_expression') === this.get('name');
   }.property('queue.default_node_label_expression'),
-  absoluteCapacity: 0,
   setCapacity: function(cap) {
     this.set('capacity', cap);
   },
@@ -244,7 +243,7 @@ App.Queue = DS.Model.extend({
 
   capacity: DS.attr('number', { defaultValue: 0 }),
   maximum_capacity: DS.attr('number', { defaultValue: 0 }),
-  //unfunded_capacity: DS.attr('number', { defaultValue: 0 }),
+  absolute_capacity: 0,
   isDirtyCapacity: false,
   isDirtyMaxCapacity: false,
 
@@ -320,5 +319,9 @@ App.Queue = DS.Model.extend({
     if (Em.isEmpty(this.get('labels').findBy('name',this.get('default_node_label_expression')))) {
       this.set('default_node_label_expression',null);
     }
-  }.observes('labels','default_node_label_expression')
+  }.observes('labels','default_node_label_expression'),
+
+  isLeafQ: function() {
+    return this.get('queues') === null;
+  }.property('queues')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/router.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/router.js
index fd996ae..d838958 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/router.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/router.js
@@ -202,12 +202,6 @@ App.ErrorRoute = Ember.Route.extend({
 
 App.CapschedRoute = Ember.Route.extend({
   actions: {
-    rollbackProp: function(prop, item) {
-      var attributes = item.changedAttributes();
-      if (attributes.hasOwnProperty(prop)) {
-        item.set(prop, attributes[prop][0]);
-      }
-    },
     saveCapSchedConfigs: function(saveMode, forceRefresh) {
       var store = this.get('store'),
         that = this,
@@ -217,7 +211,8 @@ App.CapschedRoute = Ember.Route.extend({
         advancedCtrl = this.controllerFor("capsched.advanced"),
         restartOrRefreshMap = {
           schedulerTab: schedulerCtrl.get('isRefreshOrRestartNeeded') || false,
-          queuesTab: queuesconfCtrl.get('isRefreshOrRestartNeeded') || false,
+          queuesTabRefresh: queuesconfCtrl.get('isRefreshOrRestartNeeded') || false,
+          queuesTabRestart: queuesconfCtrl.get('isQueuesMustNeedRestart') || false,
           advancedTab: advancedCtrl.get('isRefreshOrRestartNeeded') || false
         };
 
@@ -246,7 +241,8 @@ App.CapschedRoute = Ember.Route.extend({
         Em.run.bind(that,'saveConfigsError', 'save')
       ).then(function () {
         schedulerCtrl.set('isRefreshOrRestartNeeded', restartOrRefreshMap.schedulerTab);
-        queuesconfCtrl.set('isRefreshOrRestartNeeded', restartOrRefreshMap.queuesTab);
+        queuesconfCtrl.set('isRefreshOrRestartNeeded', restartOrRefreshMap.queuesTabRefresh);
+        queuesconfCtrl.set('isQueuesMustNeedRestart', restartOrRefreshMap.queuesTabRestart);
         advancedCtrl.set('isRefreshOrRestartNeeded', restartOrRefreshMap.advancedTab);
         if (opt) {
           return store.relaunchCapSched(opt);
@@ -255,6 +251,7 @@ App.CapschedRoute = Ember.Route.extend({
         if (opt) {
           schedulerCtrl.set('isRefreshOrRestartNeeded', false);
           queuesconfCtrl.set('isRefreshOrRestartNeeded', false);
+          queuesconfCtrl.set('isQueuesMustNeedRestart', false);
           advancedCtrl.set('isRefreshOrRestartNeeded', false);
         }
         return store.getRmSchedulerConfigInfo();
@@ -271,6 +268,15 @@ App.CapschedRoute = Ember.Route.extend({
         lastSavedXML = store.get('lastSavedConfigXML'),
         currentXmlConfigs = store.buildConfig('xml'),
         diffConfigs = {baseXML: lastSavedXML, newXML: currentXmlConfigs};
+
+      controller.viewConfigXmlDiff(diffConfigs);
+    },
+    viewCapSchedConfigXml: function() {
+      var store = this.get('store'),
+        controller = this.controllerFor("capsched"),
+        viewXmlConfigs = store.buildConfig('xml');
+
+      controller.viewCapSchedXml({xmlConfig: viewXmlConfigs});
     }
   },
   beforeModel: function(transition) {
@@ -383,6 +389,7 @@ App.CapschedRoute = Ember.Route.extend({
       schedulerCtrl.set('isRefreshOrRestartNeeded', false);
       advancedCtrl.set('isRefreshOrRestartNeeded', false);
       queuesconfCtrl.set('isRefreshOrRestartNeeded', false);
+      queuesconfCtrl.set('isQueuesMustNeedRestart', false);
     }).catch(
       Em.run.bind(that, 'saveConfigsError', opt)
     ).finally(function() {
@@ -398,6 +405,14 @@ App.CapschedIndexRoute = Ember.Route.extend({
   }
 });
 
+App.CapschedSchedulerRoute = Ember.Route.extend({
+  actions: {
+    didTransition: function() {
+      this.controllerFor('capsched').set('selectedQueue', null);
+    }
+  }
+});
+
 App.CapschedQueuesconfIndexRoute = Ember.Route.extend({
   beforeModel: function(transition) {
     var rootQ = this.store.getById('queue', 'root');
@@ -406,6 +421,16 @@ App.CapschedQueuesconfIndexRoute = Ember.Route.extend({
 });
 
 App.CapschedQueuesconfEditqueueRoute = Ember.Route.extend({
+  actions: {
+    willTransition: function(transition) {
+      if (this.controllerFor('capsched.queuesconf').get('isCreaingOrRenamingQueue')) {
+        transition.abort();
+      }
+    },
+    didTransition: function() {
+      this.controllerFor('capsched').set('selectedQueue', this.controller.get('model'));
+    }
+  },
   model: function(params, transition) {
     var queue = this.store.getById('queue', params.queue_id);
     if (queue) {
@@ -419,6 +444,14 @@ App.CapschedQueuesconfEditqueueRoute = Ember.Route.extend({
   }
 });
 
+App.CapschedAdvancedRoute = Ember.Route.extend({
+  actions: {
+    didTransition: function() {
+      this.controllerFor('capsched').set('selectedQueue', null);
+    }
+  }
+});
+
 App.CapschedTraceRoute = Ember.Route.extend({
   model: function() {
     return this.controllerFor('capsched').get('alertMessage');

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/styles/application.less
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/styles/application.less b/contrib/views/capacity-scheduler/src/main/resources/ui/app/styles/application.less
index bd875ba..1ab1740 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/styles/application.less
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/styles/application.less
@@ -1140,6 +1140,9 @@
     vertical-align: middle;
     font-size: 1.5em;
   }
+  .collapsible-panel-btn {
+    cursor: pointer;
+  }
 }
 
 .queue-summary {
@@ -1298,3 +1301,59 @@
 .alert-message-dialog {
   display: block;
 }
+
+.xmldiff-viewer {
+  overflow: hidden;
+  .modal-dialog {
+    width: 98%;
+    .modal-body {
+      overflow: auto;
+    }
+    .modal-footer {
+      padding: 12px 20px 0 0;
+    }
+    .viewxml-textarea {
+      resize: none;
+    }
+  }
+  table.diff {
+    th.author {
+      display: none;
+    }
+  }
+}
+
+.hierarchical-piechart {
+  .sunburst-chart {
+    position: relative;
+    path {
+      stroke: #fff;
+      stroke-width: 1.5px;
+    }
+    svg {
+      margin-left: 20px;
+    }
+    .top-container {
+      padding-bottom: 15px;
+    }
+    .queue-explanation {
+      position: absolute;
+      width: 70px;
+      text-align: center;
+      color: #666;
+      z-index: 999;
+    }
+    .percentage, .queue-name, .queue-path {
+      font-weight: bold;
+    }
+    .queue-info {
+      width: 50%;
+      display: inline-block;
+    }
+    .select-capacity-type {
+      width: 45%;
+      display: inline-block;
+      vertical-align: top;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates.js
index 2c9609f..487d09a 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates.js
@@ -60,3 +60,5 @@ require('templates/components/labelCapacityBar');
 require('templates/components/displayRootLabel');
 require('templates/components/displayLeafLabel');
 require('templates/capsched/partials/preemption');
+require('templates/components/xmldiffViewer');
+require('templates/components/sunburstChart');

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched.hbs
index 14625c1..7dc0d51 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched.hbs
@@ -40,6 +40,10 @@
   </div>
 </div>
 <div class="col-lg-4 capsched-versions-wrapper">
+  {{#if selectedQueue}}
+    {{sunburst-chart queues=queues selectedQueue=selectedQueue allNodeLabels=allNodeLabels}}
+  {{/if}}
+
   {{partial "versionsPanel"}}
 </div>
 
@@ -64,3 +68,5 @@
     </div>
   </div>
 </div>
+
+{{xmldiff-viewer diffConfig=diffXmlConfig viewConfig=viewXmlConfig}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/advanced.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/advanced.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/advanced.hbs
index 5a54d85..9973708 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/advanced.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/advanced.hbs
@@ -20,18 +20,25 @@
   {{!-- QUEUE MAPPING --}}
   {{#if isOperator}}
     <div class="hidden-sm hidden-xs">
-      {{queue-mapping mappings=scheduler.queue_mappings mappingsOverrideEnable=scheduler.queue_mappings_override_enable queues=queues isQueueMappingsDirty=isQueueMappingsDirty}}
+      {{queue-mapping mappings=scheduler.queue_mappings
+        mappingsOverrideEnable=scheduler.queue_mappings_override_enable
+        queues=queues
+        isQueueMappingsDirty=isQueueMappingsDirty
+        scheduler=scheduler
+        rollbackProp="rollbackProp"}}
     </div>
   {{/if}}
 </div>
 <div class="row">
-  <div class="btn btn-group-sm col-sm-offset-3">
+  <div class="btn btn-group-sm col-sm-offset-2">
     {{#if isQueueMappignsNeedSaveOrRefresh}}
-      {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Refresh queues is required"}}
+      {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Refresh queues is required" placement="top"}}
     {{/if}}
     <button type="button" {{bind-attr class=":btn :btn-default :btn-success isQueueMappingsDirty::disabled"}} name="saveOnly" {{action "showSaveConfigDialog"}}>Save Only</button>
     <button type="button" {{bind-attr class=":btn :btn-default :btn-success isQueueMappignsNeedSaveOrRefresh::disabled"}} name="saveRefresh" {{action "showSaveConfigDialog" "refresh"}}>Save And Refresh Queues</button>
     <button type="button" {{bind-attr class=":btn :btn-default :btn-danger isQueueMappingsDirty::disabled"}} name="cancelAdvanced" {{action "showConfirmDialog"}}>Discard Changes</button>
+    <button type="button" {{bind-attr class=":btn :btn-primary isQueueMappingsDirty::disabled"}} name="viewXmlDiff" {{action "viewConfigXmlDiff"}}>View Diff</button>
+    <button type="button" class="btn btn-default" name="viewCapSchedXml" {{action "viewCapSchedConfigXml"}}>View XML</button>
   </div>
 </div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/accessControlList.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/accessControlList.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/accessControlList.hbs
index 922e27e..f5b552a 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/accessControlList.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/accessControlList.hbs
@@ -19,12 +19,12 @@
 <div class="queue-acl-container">
   <div class="panel panel-default">
     <div class="panel-heading">
-      <div class="panel-title">
+      <div id="collapseQueueAclPanelBtn" href="#collapsibleQueueAclPanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn view.isAclPanelCollapsed:collapsed"}}>
         Access Control List
         {{#if isAnyAccessControlListDirty}}
           {{warning-info class="yellow-warning" tooltip="Need refresh queues / restart RM"}}
         {{/if}}
-        <a id="collapseQueueAclPanelBtn" href="#collapsibleQueueAclPanel" data-toggle="collapse" {{bind-attr class=":pull-right view.isAclPanelCollapsed:collapsed"}}><i {{bind-attr class=":fa view.isAclPanelCollapsed:fa-plus:fa-minus"}}></i></a>
+        <a class="pull-right"><i {{bind-attr class=":fa view.isAclPanelCollapsed:fa-plus:fa-minus"}}></i></a>
       </div>
     </div>
     <div id="collapsibleQueueAclPanel" {{bind-attr class=":panel-collapse :collapse view.isAclPanelCollapsed::in"}}>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs
index 873fb6f..429ef3f 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs
@@ -19,7 +19,7 @@
 <div class="label-capacity-container">
   <div class="panel panel-default">
     <div class="panel-heading">
-      <div class="panel-title">
+      <div id="collapseLabelCapacityPanelBtn" href="#collapsibleLabelCapacityPanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn view.isLabelsPanelCollapsed:collapsed"}}>
         Label Capacity
         {{#if isAnyChildrenQueueLabelDirty}}
           {{#if warnInvalidTotalLabelCapacity}}
@@ -28,7 +28,7 @@
             {{warning-info class="yellow-warning" tooltip="Need refresh queues / restart RM"}}
           {{/if}}
         {{/if}}
-        <a id="collapseLabelCapacityPanelBtn" href="#collapsibleLabelCapacityPanel" data-toggle="collapse" {{bind-attr class=":pull-right view.isLabelsPanelCollapsed:collapsed"}}><i {{bind-attr class=":fa view.isLabelsPanelCollapsed:fa-plus:fa-minus"}}></i></a>
+        <a class="pull-right"><i {{bind-attr class=":fa view.isLabelsPanelCollapsed:fa-plus:fa-minus"}}></i></a>
       </div>
     </div>
     <div id="collapsibleLabelCapacityPanel" {{bind-attr class=":panel-collapse :collapse view.isLabelsPanelCollapsed::in"}}>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/preemption.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/preemption.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/preemption.hbs
index d594c7e..6d398f6 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/preemption.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/preemption.hbs
@@ -19,12 +19,12 @@
 <div class="preemption-container">
   <div class="panel panel-default">
     <div class="panel-heading">
-      <div class="panel-title">
+      <div id="collapseQueuePreemptionPanelBtn" href="#collapsibleQueuePreemptionPanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn view.isPreemptionPanelCollapsed:collapsed"}}>
         Preemption
         {{#if isQueuePreemptionDirty}}
           {{warning-info class="yellow-warning" tooltip="Need refresh queues / restart RM"}}
         {{/if}}
-        <a id="collapseQueuePreemptionPanelBtn" href="#collapsibleQueuePreemptionPanel" data-toggle="collapse" {{bind-attr class=":pull-right view.isPreemptionPanelCollapsed:collapsed"}}><i {{bind-attr class=":fa view.isPreemptionPanelCollapsed:fa-plus:fa-minus"}}></i></a>
+        <a class="pull-right"><i {{bind-attr class=":fa view.isPreemptionPanelCollapsed:fa-plus:fa-minus"}}></i></a>
       </div>
     </div>
     <div id="collapsibleQueuePreemptionPanel" {{bind-attr class=":panel-collapse :collapse view.isPreemptionPanelCollapsed::in"}}>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueCapacity.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueCapacity.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueCapacity.hbs
index 608758f..fdc6800 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueCapacity.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueCapacity.hbs
@@ -19,7 +19,7 @@
 <div class="queue-capacity-container">
   <div class="panel panel-default">
     <div class="panel-heading">
-      <div class="panel-title">
+      <div id="collapseQueueCapacityPanelBtn" href="#collapsibleQueueCapacityPanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn view.isCapacityPanelCollapsed:collapsed"}}>
         Children Queue Capacites for Default Partition
         {{#if isAnyChildrenQueueCapacityDirty}}
           {{#if warnInvalidCapacity}}
@@ -28,7 +28,7 @@
             {{warning-info class="yellow-warning" tooltip="Need refresh queues / restart RM"}}
           {{/if}}
         {{/if}}
-        <a id="collapseQueueCapacityPanelBtn" href="#collapsibleQueueCapacityPanel" data-toggle="collapse" {{bind-attr class=":pull-right view.isCapacityPanelCollapsed:collapsed"}}><i {{bind-attr class=":fa view.isCapacityPanelCollapsed:fa-plus:fa-minus"}}></i></a>
+        <a class="pull-right"><i {{bind-attr class=":fa view.isCapacityPanelCollapsed:fa-plus:fa-minus"}}></i></a>
       </div>
     </div>
     <div id="collapsibleQueueCapacityPanel" {{bind-attr class=":panel-collapse :collapse view.isCapacityPanelCollapsed::in"}}>
@@ -59,13 +59,23 @@
               <div class="col-md-2 col-sm-2">
                 <label>Total Capacity</label>
               </div>
-              <div class="col-sm-5 col-md-5">
+              <div class="col-sm-4 col-md-4">
                 <div class="progress total-capacity-progress">
                   <div role="progressbar" {{bind-attr class=":progress-bar warnInvalidCapacity:progress-bar-danger:progress-bar-success" style="totalCapacityBarWidth"}}>
                     {{childrenQueuesTotalCapacity}}%
                   </div>
                 </div>
               </div>
+              <div class="col-md-3 col-sm-3">
+                <label>Absolute Capacity of Cluster</label>
+              </div>
+              <div class="col-md-3 col-sm-3">
+                <div class="progress total-capacity-progress">
+                  <div role="progressbar" class="progress-bar progress-bar-success" {{bind-attr style="absoluteClusterBarWidth"}}>
+                    {{absoluteClusterCapacity}}%
+                  </div>
+                </div>
+              </div>
             </div>
             {{#if warnInvalidCapacity}}
               <div class="row">
@@ -94,6 +104,18 @@
               </div>
             </div>
             <div class="row">
+              <div class="col-md-4 col-sm-4">
+                <label>Absolute Capacity of Cluster</label>
+              </div>
+              <div class="col-md-4 col-sm-4">
+                <div class="progress total-capacity-progress">
+                  <div role="progressbar" class="progress-bar progress-bar-success" {{bind-attr style="absoluteClusterBarWidth"}}>
+                    {{absoluteClusterCapacity}}%
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="row">
               <div class="col-md-10 col-sm-10">
                 <small><strong>For this queue:</strong> To edit capacity and maximum capacity at parent queue level</small>
                 <small>{{#link-to 'capsched.queuesconf.editqueue' parentQueue}}Click Here{{/link-to}}</small>
@@ -111,6 +133,12 @@
               <span>{{content.maximum_capacity}}%</span>
             </div>
           </div>
+          <div class="row">
+            <div class="col-md-10 col-sm-10">
+              <label>Absolute Capacity of Cluster: </label>
+              <span>{{absoluteClusterCapacity}}%</span>
+            </div>
+          </div>
         {{/if}}
       </div>
     </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueResources.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueResources.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueResources.hbs
index 809c1c0..7fc5fde 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueResources.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/queueResources.hbs
@@ -19,12 +19,12 @@
 <div class="queue-resources-container">
   <div class="panel panel-default">
     <div class="panel-heading">
-      <div class="panel-title">
+      <div id="collapseResourcesPanelBtn" href="#collapsibleQueueResourcesPanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn view.isResourcesPanelCollapsed:collapsed"}}>
         Other Configs (User Limit factor, Max AM Resource etc)
         {{#if isAnyQueueResourcesDirty}}
           {{warning-info class="yellow-warning" tooltip="Need refresh queues / restart RM"}}
         {{/if}}
-        <a id="collapseResourcesPanelBtn" href="#collapsibleQueueResourcesPanel" data-toggle="collapse" {{bind-attr class=":pull-right view.isResourcesPanelCollapsed:collapsed"}}><i {{bind-attr class=":fa view.isResourcesPanelCollapsed:fa-plus:fa-minus"}}></i></a>
+        <a class="pull-right"><i {{bind-attr class=":fa view.isResourcesPanelCollapsed:fa-plus:fa-minus"}}></i></a>
       </div>
     </div>
     <div id="collapsibleQueueResourcesPanel" {{bind-attr class=":panel-collapse :collapse view.isResourcesPanelCollapsed::in"}}>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf.hbs
index 0c70ee5..3b8ceb5 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf.hbs
@@ -22,7 +22,7 @@
       <div class="row">
         <div class="col-sm-7">
           <div class="list-group queue-hierarchy">
-            {{queue-hierarchy depth=0 queues=queues}}
+            {{queue-hierarchy depth=0 queues=queues deletedQs=deletedQueues}}
           </div>
           {{#if isOperator}}
             {{#if selectedQueue}}
@@ -81,15 +81,16 @@
     </div>
   </div>
   {{#if isOperator}}
-    <div class="btn btn-group-sm col-sm-offset-2">
-      {{#if isQueuesNeedRefreshOrRestart}}
-        {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Refresh queues / restart RM is required"}}
+    <div class="btn btn-group-sm col-sm-offset-1">
+      {{#if showNeedRefreshOrRestartWarning}}
+        {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Require refresh queues/restart RM" placement="top"}}
       {{/if}}
       <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled needSave::disabled"}} name="saveOnly" {{action "showSaveConfigDialog"}}>Save Only</button>
-      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled isQueuesNeedRefreshOrRestart::disabled"}} name="saveAndRefresh" {{action "showSaveConfigDialog" "refresh"}}>Save And Refresh Queues</button>
-      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled isQueuesNeedRefreshOrRestart::disabled"}} name="saveAndRestart" {{action "showSaveConfigDialog" "restart"}}>Save And Restart RM</button>
+      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled isDirtyQueuesNeedRefreshQsOp::disabled"}} name="saveAndRefresh" {{action "showSaveConfigDialog" "refresh"}}>Save And Refresh Queues</button>
+      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled isDirtyQueuesNeedRestartRmOp::disabled"}} name="saveAndRestart" {{action "showSaveConfigDialog" "restart"}}>Save And Restart RM</button>
       <button type="button" {{bind-attr class=":btn :btn-danger isAnyQueueDirty::disabled"}} name="cancelQueuesconfBtn" {{action "showConfirmDialog"}}>Discard Changes</button>
-      <button type="button" {{bind-attr class=":btn :btn-primary isAnyQueueDirty::disabled"}} name="viewXmlDiff" {{action "viewConfigXmlDiff"}} style="display:none;">View XML Diff</button>
+      <button type="button" {{bind-attr class=":btn :btn-primary isAnyQueueDirty::disabled"}} name="viewXmlDiff" {{action "viewConfigXmlDiff"}}>View Diff</button>
+      <button type="button" class="btn btn-default" name="viewCapSchedXml" {{action "viewCapSchedConfigXml"}}>View XML</button>
     </div>
   {{/if}}
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/scheduler.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/scheduler.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/scheduler.hbs
index 66ef1ad..26150fb 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/scheduler.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/scheduler.hbs
@@ -137,13 +137,15 @@
 </div>
 {{#if isOperator}}
   <div class="row">
-    <div class="btn btn-group-sm col-sm-offset-3">
+    <div class="btn btn-group-sm col-sm-offset-2">
       {{#if isSchedulerPropsNeedSaveOrRestart}}
-        {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Restart RM is required"}}
+        {{warning-info class="yellow-warning fa-2x resfresh-restart-warning" tooltip="Restart RM is required" placement="top"}}
       {{/if}}
       <button type="button" {{bind-attr class=":btn :btn-default :btn-success isSchedulerDirty::disabled"}} name="saveOnly" {{action 'showSaveConfigDialog'}}>Save Only</button>
       <button type="button" {{bind-attr class=":btn :btn-default :btn-success isSchedulerPropsNeedSaveOrRestart::disabled"}} name="saveRestart" {{action 'showSaveConfigDialog' 'restart'}}>Save And Restart RM</button>
       <button type="button" {{bind-attr class=":btn :btn-default :btn-danger isSchedulerDirty::disabled"}} name="cancelAdvanced" {{action 'showConfirmDialog'}}>Discard Changes</button>
+      <button type="button" {{bind-attr class=":btn :btn-primary isSchedulerDirty::disabled"}} name="viewXmlDiff" {{action "viewConfigXmlDiff"}}>View Diff</button>
+      <button type="button" class="btn btn-default" name="viewCapSchedXml" {{action "viewCapSchedConfigXml"}}>View XML</button>
     </div>
   </div>
 {{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueHierarchy.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueHierarchy.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueHierarchy.hbs
index fb34d51..e7ff559 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueHierarchy.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueHierarchy.hbs
@@ -15,7 +15,7 @@
 * limitations under the License.
 }}
 
-{{#each queue in leafQs}}
+{{#each queue in cildrenQueues}}
   {{#link-to 'capsched.queuesconf.editqueue' queue classNameBindings=":list-group-item queue.overCapacity:list-group-item-danger queue.isNew:list-group-item-info" disabled=queue.isDeletedQueue}}
     <div class="col-md-offset-{{unbound queue.depth}} col-sm-offset-{{unbound queue.depth}}">
 
@@ -35,8 +35,12 @@
         {{warn-badge}}
       {{/if}}
 
+      {{#if queue.isDeletedQueue}}
+        {{warning-info class="yellow-warning pull-right" tooltip="Queue is marked for deletion"}}
+      {{/if}}
+
       {{queue-badge q=queue class="badge pull-right"}}
     </div>
   {{/link-to}}
-  {{queue-hierarchy depth=childDepth parent=queue.path queues=queues}}
+  {{queue-hierarchy depth=childDepth parent=queue.path queues=queues deletedQs=deletedQs}}
 {{/each}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueMapping.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueMapping.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueMapping.hbs
index 33540e9..f143911 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueMapping.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueMapping.hbs
@@ -17,12 +17,12 @@
 
 <div class="panel panel-default panel-queue-mapping">
   <div class="panel-heading">
-    <div class="panel-title">
+    <div id="collapseQueueMappingsBtn" href="#queueMappingsCollapsiblePanel" data-toggle="collapse" {{bind-attr class=":panel-title :collapsible-panel-btn isCollapsed:collapsed"}}>
       Queue Mappings
       {{#if isQueueMappingsDirty}}
         {{warning-info class="yellow-warning" tooltip="Need refresh queues"}}
       {{/if}}
-      <a href="#queueMappingsCollapsiblePanel" id="collapseQueueMappingsBtn" data-toggle="collapse" {{bind-attr class=":pull-right isCollapsed:collapsed"}}><i {{bind-attr class=":fa isCollapsed:fa-plus:fa-minus"}}></i></a>
+      <a class="pull-right"><i {{bind-attr class=":fa isCollapsed:fa-plus:fa-minus"}}></i></a>
     </div>
   </div>
   <div id="queueMappingsCollapsiblePanel" {{bind-attr class=":panel-collapse :collapse isCollapsed::in"}}>
@@ -46,6 +46,11 @@
             <div class="btn-group btn-group-sm">
               <button type="button" class="btn btn-default btn-primary" name="button" {{action "showMappingOptions"}}>Add Mapping</button>
             </div>
+            {{#if isMappingsDirty}}
+              <div class="btn-group btn-group-xs">
+                <a {{action 'rollbackProp' 'queue_mappings' scheduler}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
+              </div>
+            {{/if}}
           </div>
           {{#if isShowing}}
             <div class="queue-mapping-options">
@@ -164,6 +169,11 @@
                 message='When checked, applications submitted with queues specified will be used other than those defined in configured queue mapping'
               }}
             </label>
+            {{#if isOverrideEnableDirty}}
+              <span class="btn-group btn-group-xs">
+                <a {{action 'rollbackProp' 'queue_mappings_override_enable' scheduler}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
+              </span>
+            {{/if}}
           </div>
         </div>
       </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueSummary.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueSummary.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueSummary.hbs
index a7ae9b0..fd46308 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueSummary.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/queueSummary.hbs
@@ -51,19 +51,6 @@
         </div>
         <div class="row">
           <div class="col-sm-5">
-            <label>Absolute Capacity of Cluster</label>
-          </div>
-          <div class="col-sm-5">
-            <span>{{effectiveCapacity}}%</span>
-          </div>
-          {{#if isQueueCapacityNeedRefresh}}
-            <div class="col-sm-2">
-              {{warning-info class="yellow-warning" tooltip="Need refresh queues/restart RM to take effect"}}
-            </div>
-          {{/if}}
-        </div>
-        <div class="row">
-          <div class="col-sm-5">
             <label>State</label>
           </div>
           <div class="col-sm-5">

http://git-wip-us.apache.org/repos/asf/ambari/blob/62dc775e/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/sunburstChart.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/sunburstChart.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/sunburstChart.hbs
new file mode 100644
index 0000000..462ddf7
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/sunburstChart.hbs
@@ -0,0 +1,44 @@
+{{!
+* 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="panel panel-default hierarchical-piechart">
+  <div class="panel-heading">
+    <div class="panel-title">
+      Queue Capacity Chart
+    </div>
+  </div>
+  <div class="panel-body">
+    <div id="sunburst_chart" class="sunburst-chart">
+      <div id="top_container" class="top-container">
+        <div id="queue_info" class="queue-info" style="visibility:hidden;">
+          <span>Path: </span> <span id="queuePath" class="queue-path"></span>
+        </div>
+        {{view Ember.Select
+          class="form-control input-sm select-capacity-type"
+          content=queueCapacityTypeValues
+          optionLabelPath="content.name"
+          optionValuePath="content.value"
+          value=queueCapacityTypeSelected
+        }}
+      </div>
+      <div id="explanation" class="queue-explanation" style="visibility:hidden;">
+        <span id="type_text"></span> <br/> <span id="capacityPercentage" class="percentage"></span>
+      </div>
+    </div>
+  </div>
+</div>