ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pallav...@apache.org
Subject [2/2] ambari git commit: AMBARI-17137. Capacity Scheduler View - Node label to queue mapping implementation (Akhil PB via pallavkul)
Date Wed, 06 Jul 2016 11:45:46 GMT
AMBARI-17137. Capacity Scheduler View - Node label to queue mapping implementation (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/8f5f2c66
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8f5f2c66
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8f5f2c66

Branch: refs/heads/branch-2.4
Commit: 8f5f2c66e96e4e72fa8a9d11f59c204804db66bf
Parents: 1a89d84
Author: Pallav Kulshreshtha <pallav.kul@gmail.com>
Authored: Wed Jul 6 17:14:24 2016 +0530
Committer: Pallav Kulshreshtha <pallav.kul@gmail.com>
Committed: Wed Jul 6 17:15:27 2016 +0530

----------------------------------------------------------------------
 .../src/main/resources/ui/app/components.js     |   6 +
 .../ui/app/components/confirmDiscardChanges.js  |  40 ++++++
 .../ui/app/components/displayNodeLabels.js      |  56 ++++++++
 .../ui/app/components/editLabelCapacity.js      |  75 ++++++++++
 .../ui/app/components/editQueueCapacity.js      |  48 +++++++
 .../ui/app/components/labelCapacityBar.js       |  83 +++++++++++
 .../resources/ui/app/components/queueMapping.js |  19 ++-
 .../resources/ui/app/components/queueSummary.js |   2 +-
 .../ui/app/components/saveConfigDialog.js       |  45 ++++++
 .../resources/ui/app/controllers/advanced.js    |  19 +++
 .../resources/ui/app/controllers/capsched.js    |  24 +++-
 .../resources/ui/app/controllers/editqueue.js   |  55 ++++++-
 .../resources/ui/app/controllers/queuesconf.js  | 140 ++++++++++--------
 .../resources/ui/app/controllers/scheduler.js   |  24 +++-
 .../src/main/resources/ui/app/initialize.js     |   1 -
 .../src/main/resources/ui/app/models/queue.js   |  50 ++++++-
 .../src/main/resources/ui/app/router.js         |  57 +++++++-
 .../src/main/resources/ui/app/serializers.js    |   8 +-
 .../src/main/resources/ui/app/store.js          |   2 +
 .../resources/ui/app/styles/application.less    | 142 ++++++++++++++-----
 .../src/main/resources/ui/app/templates.js      |   9 +-
 .../resources/ui/app/templates/capsched.hbs     |  21 ++-
 .../ui/app/templates/capsched/advanced.hbs      |  11 +-
 .../capsched/partials/editQueueCapacity.hbs     |  58 --------
 .../capsched/partials/labelCapacity.hbs         | 131 +++++++++++++++++
 .../capsched/partials/queueCapacity.hbs         |   2 +-
 .../ui/app/templates/capsched/queuesconf.hbs    |  44 ++----
 .../templates/capsched/queuesconf/editqueue.hbs |   4 +
 .../ui/app/templates/capsched/scheduler.hbs     |  13 +-
 .../components/confirmDiscardChanges.hbs        |  36 +++++
 .../templates/components/displayLeafLabel.hbs   |  44 ++++++
 .../templates/components/displayRootLabel.hbs   |  51 +++++++
 .../templates/components/editLabelCapacity.hbs  |  73 ++++++++++
 .../templates/components/editQueueCapacity.hbs  |  58 ++++++++
 .../templates/components/labelCapacityBar.hbs   |  41 ++++++
 .../app/templates/components/queueHierarchy.hbs |   3 +-
 .../app/templates/components/queueMapping.hbs   |   2 +-
 .../templates/components/saveConfigDialog.hbs   |  36 +++++
 .../ui/app/templates/versionsPanel.hbs          |  14 +-
 .../resources/ui/app/views/editQueueCapacity.js |  35 -----
 .../main/resources/ui/app/views/editqueue.js    |   6 +
 .../main/resources/ui/app/views/queuesconf.js   |   9 --
 42 files changed, 1318 insertions(+), 279 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 7f7bc3b..8dd7108 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
@@ -33,3 +33,9 @@ require('components/tooltipLabel');
 require('components/queueMapping');
 require('components/queueHierarchy');
 require('components/queueSummary');
+require('components/confirmDiscardChanges');
+require('components/saveConfigDialog');
+require('components/editLabelCapacity');
+require('components/editQueueCapacity');
+require('components/labelCapacityBar');
+require('components/displayNodeLabels');

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/confirmDiscardChanges.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/confirmDiscardChanges.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/confirmDiscardChanges.js
new file mode 100644
index 0000000..7ff90aa
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/confirmDiscardChanges.js
@@ -0,0 +1,40 @@
+/**
+ * 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.ConfirmDiscardChangesComponent = Ember.Component.extend({
+  layoutName: 'components/confirmDiscardChanges',
+  isDialogOpen: false,
+  actions: {
+    okay: function() {
+      this.set('isDialogOpen', false);
+      this.sendAction('action');
+    },
+    cancel: function() {
+      this.set('isDialogOpen', false);
+    }
+  },
+  watchDialog: function() {
+    if (this.get('isDialogOpen')) {
+      this.$('#confirmDiscardChangesDialog').modal('show');
+    } else {
+      this.$('#confirmDiscardChangesDialog').modal('hide');
+    }
+  }.observes('isDialogOpen')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/displayNodeLabels.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/displayNodeLabels.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/displayNodeLabels.js
new file mode 100644
index 0000000..9b31e57
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/displayNodeLabels.js
@@ -0,0 +1,56 @@
+/**
+ * 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.DisplayRootLabelComponent = Ember.Component.extend({
+  layoutName: 'components/displayRootLabel',
+
+  queueLabels: null,
+  nonAccessibleLabels: null,
+  label: null,
+  isRoot: true,
+
+  actions: {
+    enableRootLabel: function(label) {
+      var store = this.get('label.store'),
+      rootQ = store.getById('queue', 'root');
+      rootQ.addQueueNodeLabel(this.get('label'));
+    },
+    disableRootLabel: function(label) {
+      var store = this.get('label.store'),
+      rootQ = store.getById('queue', 'root');
+      rootQ.recursiveRemoveChildQueueLabels(this.get('label'));
+    }
+  },
+
+  hasQueueLabels: Ember.computed.gt('queueLabels.length', 0),
+
+  isAccessEnabled: function() {
+    if (this.get('queueLabels').contains(this.get('label'))) {
+      return true;
+    } else {
+      return false;
+    }
+  }.property('label', 'queueLabels.[]', 'nonAccessibleLabels.[]')
+});
+
+App.DisplayLeafLabelComponent = Ember.Component.extend({
+  layoutName: 'components/displayLeafLabel',
+  label: null
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editLabelCapacity.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editLabelCapacity.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editLabelCapacity.js
new file mode 100644
index 0000000..7bb3f82
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editLabelCapacity.js
@@ -0,0 +1,75 @@
+/**
+ * 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.EditLabelCapacityComponent = Ember.Component.extend({
+  layoutName: 'components/editLabelCapacity',
+
+  label: null,
+  queue: null,
+  parentQueue: null,
+
+  actions: {
+    rollbackProp: function(prop, target) {
+      var attrs = target.changedAttributes();
+      if (attrs.hasOwnProperty(prop)) {
+        target.set(prop, attrs[prop][0]);
+      }
+    },
+    enableAccess: function() {
+      this.get('queue').addQueueNodeLabel(this.get('label'));
+    },
+    disableAccess: function() {
+      this.get('label').set('capacity', 0);
+      this.get('queue').recursiveRemoveChildQueueLabels(this.get('label'));
+    }
+  },
+
+  isAccessEnabled: function() {
+    if (this.get('queue.labels').findBy('name',this.get('label.name'))) {
+      return true;
+    } else {
+      return false;
+    }
+  }.property('queue', 'queue.labels.[]'),
+
+  isAccessDisabled: Ember.computed.not('isAccessEnabled'),
+
+  isDisabledByParent: function() {
+    if (Ember.isEmpty(this.get('parentQueue'))) {
+      return false;
+    } else {
+      return !this.get('parentQueue.labels').findBy('name', this.get('label.name'));
+    }
+  }.property('parentQueue', 'parentQueue.labels.[]'),
+
+  isLabelCapacityDirty: function() {
+    return this.get('label').changedAttributes().hasOwnProperty('capacity');
+  }.property('label.capacity'),
+
+  isLabelMaxCapacityDirty: function() {
+    return this.get('label').changedAttributes().hasOwnProperty('maximum_capacity');
+  }.property('label.maximum_capacity'),
+
+  isInvalidLabelMaxCapacity: function() {
+    var invalid = this.get('label.maximum_capacity') < this.get('label.capacity');
+    this.get('queue').set('isInvalidLabelMaxCapacity', invalid);
+    return invalid;
+  }.property('label.capacity', 'label.maximum_capacity')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editQueueCapacity.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editQueueCapacity.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editQueueCapacity.js
new file mode 100644
index 0000000..b244097
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/editQueueCapacity.js
@@ -0,0 +1,48 @@
+/**
+ * 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.EditQueueCapacityComponent = Ember.Component.extend({
+  layoutName: 'components/editQueueCapacity',
+  queue: null,
+  warnInvalidTotalCapacity: false,
+
+  actions: {
+    rollbackProp: function(prop, target) {
+      var attrs = target.changedAttributes();
+      if (attrs.hasOwnProperty(prop)) {
+        target.set(prop, attrs[prop][0]);
+      }
+    }
+  },
+
+  isQueueCapacityDirty: function() {
+    return this.get('queue').changedAttributes().hasOwnProperty('capacity');
+  }.property('queue.capacity'),
+
+  isQueueMaximumCapacityDirty: function() {
+    return this.get('queue').changedAttributes().hasOwnProperty('maximum_capacity');
+  }.property('queue.maximum_capacity'),
+
+  isInvalidQueueMaximumCapacity: function() {
+    var isInvalid = this.get('queue.maximum_capacity') < this.get('queue.capacity');
+    this.get('queue').set('isInvalidMaxCapacity', isInvalid);
+    return isInvalid;
+  }.property('queue.capacity', 'queue.maximum_capacity')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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
new file mode 100644
index 0000000..89e7cac
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/labelCapacityBar.js
@@ -0,0 +1,83 @@
+/**
+ * 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.LabelCapacityBarComponent = Ember.Component.extend({
+  layoutName: 'components/labelCapacityBar',
+  queueLabels: null,
+  labels: null,
+  queues: null,
+
+  extractLabels: function() {
+    var qLabels = this.get('queueLabels'),
+    labels = [], queues = [];
+    qLabels.forEach(function(labelObj) {
+      labels.pushObject(labelObj.label);
+      queues.pushObject(labelObj.queue);
+    });
+    this.set('labels', labels);
+    this.set('queues', queues);
+  }.observes('queueLabels.length').on('init'),
+
+  childrenQueueLabelsTotalCapacity: function() {
+    var labels = this.get('labels'),
+    totalCapacity = 0;
+    labels.forEach(function(label){
+      totalCapacity += label.get('capacity');
+    });
+    return totalCapacity;
+  }.property('labels.length', 'labels.@each.capacity'),
+
+  widthPattern: 'width: %@%',
+
+  warnInvalidLabelCapacity: function() {
+    var totalCap = this.get('childrenQueueLabelsTotalCapacity');
+    var isInvalid = false;
+    if (totalCap > 100 || totalCap < 100) {
+      isInvalid = true;
+    }
+    this.get('labels').setEach('overCapacity', isInvalid);
+    return isInvalid;
+  }.property('childrenQueueLabelsTotalCapacity'),
+
+  totalLabelCapacityBarWidth: function() {
+    var totalCap = this.get('childrenQueueLabelsTotalCapacity');
+    if (totalCap > 100) {
+      totalCap = 100;
+    }
+    return this.get('widthPattern').fmt(totalCap);
+  }.property('childrenQueueLabelsTotalCapacity'),
+
+  isAnyQueueLabelsEnabled: function() {
+    var qlabels = [],
+    isAnyEnabled = false;
+    this.get('queues').forEach(function(qq){
+      qq.get('labels').forEach(function(lab){
+        qlabels.addObject(lab);
+      });
+    });
+    this.get('labels').forEach(function(label){
+      if (qlabels.contains(label)) {
+        isAnyEnabled = true;
+        return false;
+      }
+    });
+    return isAnyEnabled;
+  }.property('queues.@each.labels.[]')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 bbf0cab..8118805 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
@@ -22,8 +22,8 @@
    layoutName: 'components/queueMapping',
 
    queues: null,
-   mappings: '',
-   mappingsOverrideEnable: false,
+   mappings: null,
+   mappingsOverrideEnable: null,
 
    isShowing: false,
    queueMappings: [],
@@ -47,6 +47,9 @@
      },
      removeQueueMapping: function(qm){
        this.get('queueMappings').removeObject(qm);
+     },
+     toggleMappingOverride: function() {
+       this.toggleProperty('mappingsOverrideEnable');
      }
    },
 
@@ -57,10 +60,12 @@
    },
 
    parseMappings: function(){
-     var mappings = this.get('mappings') || '';
-     this.set('queueMappings', mappings.split(',').filter(function(mapping){
-       return mapping !== "";
-     }) || []);
+     var mappings = this.get('mappings') || null;
+     if (mappings) {
+       this.set('queueMappings', mappings.split(',').filter(function(mapping){
+         return mapping !== "";
+       }) || []);
+     }
    }.observes('mappings').on('init'),
 
    extractLeafQueueNames: function(){
@@ -91,7 +96,7 @@
    },
 
    queueMappingsDidChange: function(){
-     var csMappings = this.get('queueMappings').join(',') || '';
+     var csMappings = this.get('queueMappings').join(',') || null;
      this.set('mappings', csMappings);
    }.observes('queueMappings', 'queueMappings.length', 'queueMappings.@each'),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 113ad13..bfcd4b6 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
@@ -65,7 +65,7 @@
        currentQ = allQueues.findBy('id', currentQ.get('parentPath').toLowerCase()) || null;
      }
      var effectiveCapacityPercent = effectiveCapacityRatio * 100;
-     this.get('queue').set('absolute_capacity', effectiveCapacityPercent || null);
+     this.get('queue').set('absolute_capacity', effectiveCapacityPercent || 0);
      return effectiveCapacityPercent;
    }.property('queue.capacity', 'allQueues.@each.capacity', 'allQueues.length')
  });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/saveConfigDialog.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/saveConfigDialog.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/saveConfigDialog.js
new file mode 100644
index 0000000..ea5262d
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/components/saveConfigDialog.js
@@ -0,0 +1,45 @@
+/**
+ * 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.SaveConfigDialogComponent = Ember.Component.extend({
+ layoutName: 'components/saveConfigDialog',
+ isDialogOpen: false,
+ configNote: '',
+ param: '',
+
+ actions: {
+   saveConfigs: function() {
+     this.set('isDialogOpen', false);
+     var mode = this.get('param');
+     this.sendAction('action', mode);
+   },
+   closeDialog: function() {
+     this.set('isDialogOpen', false);
+   }
+ },
+
+ watchDialog: function() {
+   if (this.get('isDialogOpen')) {
+     this.$('#configNoteModalDialog').modal('show');
+   } else {
+     this.$('#configNoteModalDialog').modal('hide');
+   }
+ }.observes('isDialogOpen')
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 7af45bb..edd8a3b 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
@@ -33,15 +33,34 @@ App.CapschedAdvancedController = Ember.Controller.extend({
           sched.set(prop, attributes[prop][0]);
         }
       });
+    },
+    showSaveConfigDialog: function(mode) {
+      if (mode) {
+        this.set('saveMode', mode);
+      } else {
+        this.set('saveMode', '');
+      }
+      this.set('isSaveConfigDialogOpen', true);
+    },
+    showConfirmDialog: function() {
+      this.set('isConfirmDialogOpen', true);
     }
   },
 
   isOperator: cmp.alias('controllers.capsched.isOperator'),
   scheduler: cmp.alias('controllers.capsched.content'),
   queues: cmp.alias('controllers.capsched.queues'),
+
   isQueueMappingsDirty: false,
   queueMappingProps: ['queue_mappings', 'queue_mappings_override_enable'],
 
+  saveMode: '',
+
+  isConfirmDialogOpen: false,
+  isSaveConfigDialogOpen: false,
+
+  configNote: cmp.alias('store.configNote'),
+
   queueMappingsDidChange: function() {
     var sched = this.get('scheduler'),
     attributes = sched.changedAttributes(),

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 1ee7a6b..545d348 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
@@ -18,11 +18,16 @@
 
 var App = require('app');
 
-var cmp = Ember.computed;
-
 App.CapschedController = Ember.Controller.extend({
   actions: {
-
+    loadTagged: function (tag) {
+      this.transitionToRoute('capsched.scheduler').then(function() {
+         this.store.fetchTagged(App.Queue, tag);
+       }.bind(this));
+    },
+    clearAlert: function () {
+      this.set('alertMessage',null);
+    },
   },
 
   /**
@@ -35,5 +40,16 @@ App.CapschedController = Ember.Controller.extend({
    * Inverted isOperator value.
    * @type {Boolean}
    */
-  isNotOperator: cmp.not('isOperator')
+  isNotOperator: Ember.computed.not('isOperator'),
+
+  alertMessage: null,
+
+  tags: function () {
+    return this.store.find('tag');
+  }.property('store.current_tag'),
+
+  sortedTags: Ember.computed.sort('tags', function(a, b){
+    return (+a.id > +b.id)? (+a.id < +b.id)? 0 : -1 : 1;
+  })
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 518b677..f42d2e4 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
@@ -27,6 +27,7 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
   isNotOperator: Ember.computed.not('isOperator'),
   scheduler: Ember.computed.alias('controllers.capsched.content'),
   allQueues: Ember.computed.alias('controllers.capsched.queues'),
+  isNodeLabelsEnabledByRM: Ember.computed.alias('store.isNodeLabelsEnabledByRM'),
 
   isRangerEnabledForYarn: function() {
     var isRanger = this.get('controllers.capsched.isRangerEnabledForYarn');
@@ -315,7 +316,7 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
     },
 
     /**
-     * Array of leaf queues.
+     * Array of children queues.
      * @return {Array}
      */
     childrenQueues: function () {
@@ -385,5 +386,55 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
    propertyBecomeDirty: function (controller, property) {
      var queueProp = property.split('.').objectAt(1);
      this.set('queueDirtyFields.' + queueProp, this.get('content').changedAttributes().hasOwnProperty(queueProp));
-   }
+   },
+
+   allNodeLabels: Ember.computed.alias('store.nodeLabels.content'),
+   queueNodeLabels: Ember.computed.alias('content.sortedLabels'),
+   hasQueueLabels: Ember.computed.gt('content.sortedLabels.length', 0),
+   nonAccessibleLabels: Ember.computed.alias('content.nonAccessibleLabels'),
+   allLabelsForQueue: Ember.computed.union('queueNodeLabels', 'nonAccessibleLabels'),
+   hasAnyNodeLabelsForQueue: Ember.computed.gt('allLabelsForQueue.length', 0),
+
+   accessibleLabelNames: function() {
+     var labels = this.get('queueNodeLabels'),
+     len = this.get('queueNodeLabels.length'),
+     labelNames = ['None'];
+     if (len > 0) {
+       labelNames = labels.map(function(label){
+         return label.get('name');
+       });
+     }
+     return labelNames.join(", ");
+   }.property('content', 'queueNodeLabels.[]'),
+
+   childrenQueueLabels: function() {
+     var childrenQs = this.get('childrenQueues'),
+     allNodeLabels = this.get('allNodeLabels'),
+     chidrenQLabels = [],
+     ctrl = this;
+     allNodeLabels.forEach(function(label) {
+       var labelName = label.name,
+       labelGroup = {
+         labelName: labelName,
+         childrenQueueLabels: []
+       };
+       childrenQs.forEach(function(queue) {
+         var qLabel = ctrl.store.getById('label', [queue.get('path'), labelName].join('.')),
+         parentQ = ctrl.store.getById('queue', queue.get('parentPath').toLowerCase());
+         var cql = {
+           label: qLabel,
+           queue: queue,
+           parentQueue: parentQ
+         };
+         labelGroup.childrenQueueLabels.pushObject(cql);
+       });
+       if (labelGroup.childrenQueueLabels.length > 0) {
+         chidrenQLabels.pushObject(labelGroup);
+       }
+     });
+     return chidrenQLabels;
+   }.property('childrenQueues.length', 'childrenQueues.@each.labels.[]', 'content.labels.length'),
+
+   hasChildrenQueueLabels: Ember.computed.gt('childrenQueueLabels.length', 0)
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 93f6645..683bc6f 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
@@ -25,6 +25,8 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
   needs: ['capsched', 'loading'],
   queues: Ember.computed.alias('controllers.capsched.queues'),
   isOperator: Ember.computed.alias('controllers.capsched.isOperator'),
+  allNodeLabels: Ember.computed.alias('store.nodeLabels.content'),
+  allNodeLabelRecords: [],
 
   actions: {
     addNewQueue: function() {
@@ -65,36 +67,7 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
         maximum_capacity: qCapacity
       });
       this.set('newQueue', newQueue);
-      store.saveAndUpdateQueue(newQueue)
-      .then(Em.run.bind(this, 'saveAndUpdateQueueSuccess', newQueue))
-      .catch(Em.run.bind(this, 'saveQueuesConfigError', 'createQueue'));
-    },
-    saveQueuesConfig: function(saveMode) {
-      var that = this;
-      var collectedLabels = this.get('queues').reduce(function (prev, q) {
-        return prev.pushObjects(q.get('labels.content'));
-      },[]);
-
-      var store = this.get('store'),
-      optn = '',
-      saveQs = this.get('queues').save(),
-      labels = DS.ManyArray.create({content:collectedLabels}).save();
-
-      if (saveMode === 'refresh') {
-        optn = 'saveAndRefresh';
-      } else if (saveMode === 'restart') {
-        optn = 'saveAndRestart';
-      }
-
-      Ember.RSVP.Promise.all([labels, saveQs])
-      .then(Em.run.bind(that, 'saveQueuesConfigSuccess'))
-      .then(function() {
-        if (optn) {
-          return store.relaunchCapSched(optn);
-        }
-      })
-      .then(Em.run.bind(that, 'relaunchCapSchedSuccess', optn))
-      .catch(Em.run.bind(that, 'saveQueuesConfigError', optn));
+      store.saveAndUpdateQueue(newQueue).then(Em.run.bind(this, 'saveAndUpdateQueueSuccess', newQueue));
     },
     clearCreateQueue: function() {
       this.set('newQueueName', '');
@@ -102,11 +75,30 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
       this.set('isInvalidQueueName', false);
       this.set('invalidQueueNameMessage', '');
     },
-    clearAlert: function () {
-      this.set('alertMessage', null);
-    },
-    cancelQueuesChanges: function() {
-
+    discardQueuesChanges: function() {
+      var allQueues = this.get('queues');
+      allQueues.forEach(function(qq){
+        var qAttrs = qq.changedAttributes();
+        for (var qProp in qAttrs) {
+          if (qAttrs.hasOwnProperty(qProp)) {
+            qq.set(qProp, qAttrs[qProp][0]);
+          }
+        }
+        var labels = qq.get('labels');
+        labels.forEach(function(lb){
+          var lbAttrs = lb.changedAttributes();
+          for (var lbProp in lbAttrs) {
+            if (lbAttrs.hasOwnProperty(lbProp)) {
+              lb.set(lbProp, lbAttrs[lbProp][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);
+        }
+      });
     },
     stopQueue: function() {
       this.set('selectedQueue.state', _stopState);
@@ -124,6 +116,17 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
       .then(Em.run.schedule('afterRender', function () {
         that.get('store').recurceRemoveQueue(delQ);
       }));
+    },
+    showSaveConfigDialog: function(mode) {
+      if (mode) {
+        this.set('saveMode', mode);
+      } else {
+        this.set('saveMode', '');
+      }
+      this.set('isSaveConfigDialogOpen', true);
+    },
+    showConfirmDialog: function() {
+      this.set('isConfirmDialogOpen', true);
     }
   },
 
@@ -161,6 +164,28 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     this.validateQueueName();
   }.observes('newQueueName', 'newQueueName.length'),
 
+  initNodeLabelRecords: function() {
+    var allQs = this.get('queues'),
+    allLabels = this.get('allNodeLabels'),
+    store = this.get('store'),
+    records = [],
+    nonAccessible = [],
+    ctrl = this;
+    allQs.forEach(function(queue) {
+      nonAccessible = [];
+      allLabels.forEach(function(label) {
+        var qLabel = store.getById('label', [queue.get('path'), label.name].join('.'));
+        if (!queue.get('labels').contains(qLabel)) {
+          nonAccessible.pushObject(qLabel);
+        }
+        records.pushObject(qLabel);
+      });
+      queue.set('nonAccessibleLabels', nonAccessible);
+    });
+    this.set('allNodeLabelRecords', records);
+
+  }.on('init'),
+
   /**
    * Marks each queue in leaf with 'overCapacity' if sum if their capacity values is greater than 100.
    * @method capacityControl
@@ -192,7 +217,15 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
    * Check properties for refresh requirement
    * @type {Boolean}
    */
-  needRefreshProps: Ember.computed.any('hasChanges', 'hasNewQueues'),
+  needRefreshProps: Ember.computed.any('hasChanges', 'hasNewQueues', 'hasDirtyNodeLabels'),
+
+  dirtyNodeLabels: function() {
+    return this.get('allNodeLabelRecords').filter(function (label) {
+      return label.get('isDirty');
+    });
+  }.property('allNodeLabelRecords.@each.isDirty'),
+
+  hasDirtyNodeLabels: Ember.computed.notEmpty('dirtyNodeLabels.[]'),
 
   /**
    * List of modified queues.
@@ -250,7 +283,7 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
    * check if can save configs
    * @type {bool}
    */
-  canNotSave: Em.computed.any('hasOverCapacity', 'hasInvalidMaxCapacity', 'hasUncompetedAddings', 'hasNotValid', 'hasNotValidLabels'),
+  canNotSave: Em.computed.any('hasOverCapacity', 'hasInvalidMaxCapacity', 'hasInvalidLabelMaxCapacity', 'hasIncompletedAddings', 'hasNotValid', 'hasNotValidLabels'),
 
   /**
    * List of not valid queues.
@@ -292,19 +325,25 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
    * True if any queue has invalid max capacity (if max_cappacity < capacity).
    * @type {Boolean}
    */
-  hasInvalidMaxCapacity: Em.computed.filterBy('queues', 'isInvalidMaxCapacity', true),
+  hasInvalidMaxCapacity: function() {
+    return this.get('queues').anyBy('isInvalidMaxCapacity', true);
+  }.property('queues.@each.isInvalidMaxCapacity'),
+
+  hasInvalidLabelMaxCapacity: function() {
+    return this.get('queues').anyBy('isInvalidLabelMaxCapacity', true);
+  }.property('queues.@each.isInvalidLabelMaxCapacity'),
 
   /**
    * List of queues with incomplete adding process
    * @type {[type]}
    */
-  uncompetedAddings: Em.computed.filterBy('queues', 'isNew', true),
+  incompletedAddings: Em.computed.filterBy('queues', 'isNew', true),
 
   /**
    * True if uncompetedAddings is not empty.
    * @type {Boolean}
    */
-  hasUncompetedAddings: Em.computed.notEmpty('uncompetedAddings.[]'),
+  hasIncompletedAddings: Em.computed.notEmpty('incompletedAddings.[]'),
 
   /**
    * Represents queue run state. Returns true if state is null.
@@ -341,22 +380,12 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
      return !this.get('isRootQSelected') && !this.get('isSelectedQRunning');
    }.property('isRootQSelected', 'isSelectedQRunning'),
 
-   /**
-    * Property for error message which may appear when saving queue.
-    * @type {Object}
-    */
-   alertMessage: null,
-
    configNote: Ember.computed.alias('store.configNote'),
+   saveMode: '',
+
+   isSaveConfigDialogOpen: false,
+   isConfirmDialogOpen: false,
 
-   saveQueuesConfigSuccess: function() {
-     this.set('store.deletedQueues', []);
-   },
-   saveQueuesConfigError: function(operation, error) {
-     var response = (error && error.responseJSON)? error.responseJSON : {};
-     response.simpleMessage = operation.capitalize() + ' failed!';
-     this.set('alertMessage', response);
-   },
    saveAndUpdateQueueSuccess: function(newQ) {
      var parentPath = newQ.get('parentPath'),
      parentQ = this.store.getById('queue', parentPath.toLowerCase()),
@@ -365,8 +394,5 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
      pQueues.sort();
      parentQ.set('queues', pQueues.join(","));
      this.set('newQueue', null);
-   },
-   relaunchCapSchedSuccess: function(opt) {
-
    }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 c0c56b6..6638b4c 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
@@ -22,6 +22,7 @@ var cmp = Ember.computed;
 
 App.CapschedSchedulerController = Ember.Controller.extend({
   needs: ['capsched'],
+  scheduler: cmp.alias('controllers.capsched.content'),
   schedulerProps: ['maximum_am_resource_percent', 'maximum_applications', 'node_locality_delay', 'resource_calculator'],
 
   actions: {
@@ -34,16 +35,29 @@ App.CapschedSchedulerController = Ember.Controller.extend({
           sched.set(prop, attributes[prop][0]);
         }
       });
+    },
+    showConfirmDialog: function() {
+      this.set('isConfirmDialogOpen', true);
+    },
+    showSaveConfigDialog: function(mode) {
+      if (mode) {
+        this.set('saveMode', mode);
+      } else {
+        this.set('saveMode', '');
+      }
+      this.set('isSaveConfigDialogOpen', true);
     }
   },
 
   isOperator: cmp.alias('controllers.capsched.isOperator'),
 
-  /**
-   * Scheduler record
-   * @type {App.Scheduler}
-   */
-  scheduler: cmp.alias('controllers.capsched.content'),
+  saveMode: '',
+
+  isConfirmDialogOpen: false,
+  isSaveConfigDialogOpen: false,
+
+  configNote: cmp.alias('store.configNote'),
+
   isSchedulerDirty: false,
 
   schedulerBecomeDirty: function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/initialize.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/initialize.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/initialize.js
index 3dfe363..b485793 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/initialize.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/initialize.js
@@ -48,7 +48,6 @@ require('models');
 //views
 require('views/queues');
 require('views/editqueue');
-require('views/editQueueCapacity');
 require('views/queuesconf');
 
 // routes

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 45146ef..e91c90f 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
@@ -35,7 +35,8 @@ App.Label = DS.Model.extend({
   }.property('store.nodeLabels.content.@each.notExist'),
   isDefault: function () {
     return this.get('queue.default_node_label_expression') === this.get('name');
-  }.property('queue.default_node_label_expression')
+  }.property('queue.default_node_label_expression'),
+  absoluteCapacity: 0
 });
 
 App.Scheduler = DS.Model.extend({
@@ -145,6 +146,43 @@ App.Queue = DS.Model.extend({
     }
   },
 
+  removeQueueNodeLabel: function(qLabel) {
+    qLabel = this.get('labels').findBy('name', qLabel.get('name'));
+    if (qLabel) {
+      if (this.get('labels').contains(qLabel)) {
+        this.get('labels').removeObject(qLabel);
+      }
+      if (!this.get('nonAccessibleLabels').contains(qLabel)) {
+        this.get('nonAccessibleLabels').addObject(qLabel);
+      }
+      this.notifyPropertyChange('labels');
+      this.notifyPropertyChange('nonAccessibleLabels');
+    }
+  },
+
+  recursiveRemoveChildQueueLabels: function(qLabel) {
+    qLabel = this.get('labels').findBy('name', qLabel.get('name'));
+    if (qLabel) {
+      this.removeQueueNodeLabel(qLabel);
+      var childrenQs = this.store.all('queue').filterBy('depth', this.get('depth') + 1).filterBy('parentPath', this.get('path'));
+      childrenQs.forEach(function(child){
+        child.recursiveRemoveChildQueueLabels(qLabel);
+      }.bind(this));
+    }
+  },
+
+  addQueueNodeLabel: function(qLabel) {
+    qLabel = this.store.getById('label', [this.get('path'), qLabel.get('name')].join('.'));
+    if (!this.get('labels').contains(qLabel)) {
+      this.get('labels').addObject(qLabel);
+    }
+    if (this.get('nonAccessibleLabels').contains(qLabel)) {
+      this.get('nonAccessibleLabels').removeObject(qLabel);
+    }
+    this.notifyPropertyChange('labels');
+    this.notifyPropertyChange('nonAccessibleLabels');
+  },
+
   isAnyDirty: function () {
     return this.get('isDirty') || !Em.isEmpty(this.get('labels').findBy('isDirty',true)) || this.get('isLabelsDirty');
   }.property('isDirty','labels.@each.isDirty','initialLabels','isLabelsDirty'),
@@ -153,6 +191,13 @@ App.Queue = DS.Model.extend({
   labelsLoad:function() {
     this.set('labelsEnabled',this._data.labelsEnabled);
     this.set('initialLabels',this.get('labels').mapBy('id'));
+
+    //Setting root label capacity to 100
+    if (this.get('id') === 'root') {
+      this.get('labels').forEach(function(label){
+        label.set('capacity', 100);
+      });
+    }
   }.on('didLoad','didUpdate','didCreate'),
 
   isLabelsDirty:function () {
@@ -211,6 +256,9 @@ App.Queue = DS.Model.extend({
   }.property('_overCapacity','labels.@each.overCapacity'),
 
   isInvalidMaxCapacity: false,
+  isInvalidLabelMaxCapacity: false,
+
+  nonAccessibleLabels: [],
 
   //new queue flag
   isNewQueue:DS.attr('boolean', {defaultValue: false}),

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 a32e02c..49363d4 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
@@ -23,15 +23,17 @@ App.Router.map(function() {
     this.resource('queue', { path: '/:queue_id' });
     this.resource('trace', { path: '/log' });
   });
+  this.route('refuse');
+
   this.resource('capsched', {path: '/capacity-scheduler'}, function() {
     this.route('scheduler', {path: '/scheduler'});
     this.route('advanced', {path: '/advanced'});
     this.route('trace', {path: '/log'});
+    this.route('refuse', {path: '/refuse'});
     this.route('queuesconf', {path: '/queues'}, function() {
       this.route('editqueue', {path: '/:queue_id'});
     });
   });
-  this.route('refuse');
 });
 
 var RANGER_SITE = 'ranger-yarn-plugin-properties';
@@ -203,6 +205,36 @@ App.CapschedRoute = Ember.Route.extend({
       if (attributes.hasOwnProperty(prop)) {
         item.set(prop, attributes[prop][0]);
       }
+    },
+    saveCapSchedConfigs: function(saveMode) {
+      var store = this.get('store'),
+        that = this,
+        capschedCtrl = this.controllerFor("capsched");
+
+      var collectedLabels = capschedCtrl.get('queues').reduce(function (prev,q) {
+        return prev.pushObjects(q.get('labels.content'));
+      },[]);
+
+      var scheduler = capschedCtrl.get('content').save(),
+          queues = capschedCtrl.get('queues').save(),
+          labels = DS.ManyArray.create({content: collectedLabels}).save(),
+          opt = '';
+
+      if (saveMode == 'restart') {
+        opt = 'saveAndRestart';
+      } else if (saveMode == 'refresh') {
+        opt = 'saveAndRefresh';
+      }
+
+      Em.RSVP.Promise.all([labels, queues, scheduler]).then(
+        Em.run.bind(that,'saveConfigsSuccess'),
+        Em.run.bind(that,'saveConfigsError', 'save')
+      ).then(function () {
+        if (opt) {
+          return store.relaunchCapSched(opt);
+        }
+      })
+      .catch(Em.run.bind(this,'saveConfigsError', opt));
     }
   },
   beforeModel: function(transition) {
@@ -252,6 +284,23 @@ App.CapschedRoute = Ember.Route.extend({
         reject(e);
       });
     }, 'App: CapschedRoute#model');
+  },
+  loadingError: function (transition, error) {
+    var refuseController = this.container.lookup('controller:capsched.refuse') || this.generateController('capsched.refuse'),
+        message = error.responseJSON || {'message': 'Something went wrong.'};
+
+    transition.abort();
+    refuseController.set('model', message);
+    this.transitionTo('refuse');
+  },
+  saveConfigsSuccess: function() {
+    this.set('store.deletedQueues', []);
+  },
+  saveConfigsError: function(operation, err) {
+    var response = error.responseJSON || {};
+    response.simpleMessage = operation.capitalize() + ' failed!';
+    this.controllerFor("capsched").set('alertMessage', response);
+    throw Error(err);
   }
 });
 
@@ -274,3 +323,9 @@ App.CapschedQueuesconfEditqueueRoute = Ember.Route.extend({
     this.controllerFor('capsched.queuesconf').set('selectedQueue', model);
   }
 });
+
+App.CapschedTraceRoute = Ember.Route.extend({
+  model: function() {
+    return this.controllerFor('capsched.queuesconf').get('alertMessage');
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js
index 7fef4be..c3976b4 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/serializers.js
@@ -160,12 +160,13 @@ App.SerializerMixin = Em.Mixin.create({
       nodeLabels.forEach(function(label) {
         var labelId = [queue.id,label.name].join('.'),
             cp =  [prefix, queue.path, 'accessible-node-labels',label.name,'capacity'].join('.'),
-            mcp = [prefix, queue.path, 'accessible-node-labels',label.name,'maximum-capacity'].join('.');
+            mcp = [prefix, queue.path, 'accessible-node-labels',label.name,'maximum-capacity'].join('.'),
+            labelCapacity = properties.hasOwnProperty(cp)?+properties[cp]:0;
         labels.push({
           id:labelId,
-          capacity:properties.hasOwnProperty(cp)?+properties[cp]:0,
+          capacity:labelCapacity,
           maximum_capacity:properties.hasOwnProperty(mcp)?+properties[mcp]:100,
-          queue:(queue.labels.contains([queue.id,label.name].join('.')))?queue.id:null
+          queue:(queue.labels.contains(labelId))?queue.id:null
         });
       });
 
@@ -306,4 +307,3 @@ App.ConfigSerializer = DS.RESTSerializer.extend({
     return resourceHash;
   }
 });
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js
index 44b5800..4a9c6b0 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/store.js
@@ -303,6 +303,8 @@ App.ApplicationStore = DS.Store.extend({
 
   isRmOffline:false,
 
+  isNodeLabelsEnabledByRM: false,
+
   isInitialized: Ember.computed.and('tag', 'clusterName'),
 
   relaunchCapSched: function (opt) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 9952045..e849ad4 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
@@ -1040,43 +1040,17 @@
     padding: 7px 6px;
     width: 26px;
   }
-}
-
-.queue-summary {
-  .panel-default {
-    border-color: #f5f5f5;
-  }
-}
-
-.queue-capacity-container {
-  .form-inline {
-    margin-bottom: 20px;
-    .queue-name {
-      margin-top: 5px;
-    }
-    .capacity-input-percent {
-      width: 30%;
-      float: left;
-      display: inline-block;
-      input {
-        width: 60%;
-      }
-    }
-    .capacity-input-slider {
-      width: 60%;
-      display: inline-block;
-    }
+  .yellow-warning {
+    color: #f0ad4e;
   }
-  .progress {
+  .display-inline {
     display: inline-block;
-    vertical-align: middle;
-    margin-bottom: 0;
-    .progress-bar {
-      color: #000;
-    }
   }
-  .total-capacity-progress {
-    width: 100%;
+  .btn-small {
+    padding: 1px 5px;
+    font-size: 12px;
+    line-height: 1.5;
+    border-radius: 3px;
   }
   input[type=range] {
     -webkit-appearance: none;
@@ -1157,6 +1131,44 @@
   }
 }
 
+.queue-summary {
+  .panel-default {
+    border-color: #f5f5f5;
+  }
+}
+
+.queue-capacity-container {
+  .form-inline {
+    margin-bottom: 20px;
+    .queue-name {
+      margin-top: 5px;
+    }
+    .capacity-input-percent {
+      width: 25%;
+      float: left;
+      display: inline-block;
+      input {
+        width: 60%;
+      }
+    }
+    .capacity-input-slider {
+      width: 50%;
+      display: inline-block;
+    }
+  }
+  .progress {
+    display: inline-block;
+    vertical-align: middle;
+    margin-bottom: 0;
+    .progress-bar {
+      color: #000;
+    }
+  }
+  .total-capacity-progress {
+    width: 100%;
+  }
+}
+
 .edit-queuename-wrapper {
   margin-top: 10px;
   margin-bottom: 20px;
@@ -1176,6 +1188,64 @@
   }
 }
 
-.yellow-warning {
-  color: #f0ad4e;
+.label-capacity-container {
+  .labels-inline-list {
+    display: inline-block;
+  }
+  .border-wrapper {
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    padding: 10px;
+    margin-bottom: 10px;
+  }
+  .label-capacity-input {
+    width: 35%;
+    input {
+      width: 60% !important;
+    }
+    .input-group-addon {
+      float: left;
+    }
+  }
+  .label-capacity-rollback {
+    margin-left: -6px;
+  }
+  .node-label-item {
+    margin-bottom: 10px;
+  }
+  .access-disabled {
+    color: #ccc;
+    background-color: #f9f9f9!important;
+  }
+  .total-capacity-progress {
+    .progress-bar {
+      color: #000;
+    }
+  }
+  .total-label {
+    font-size: 13.5px;
+  }
+  .label-capacity-slider {
+    width: 54%;
+    display: inline-block;
+  }
+}
+
+.capsched-versions-wrapper {
+  padding-top: 40px;
+  padding-left: 0;
+}
+
+.capsched-versions-panel {
+  .panel-heading {
+    margin-bottom: -1px;
+  }
+  .panel-body {
+    padding: 0px 15px 5px 15px;
+    max-height: 428px;
+    overflow-y: auto;
+  }
+  .table {
+    margin-bottom: 0;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 17b279a..6e310ad 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
@@ -51,4 +51,11 @@ require('templates/components/queueSummary');
 require('templates/capsched/partials/queueResources');
 require('templates/capsched/partials/accessControlList');
 require('templates/capsched/partials/queueCapacity');
-require('templates/capsched/partials/editQueueCapacity');
+require('templates/components/editQueueCapacity');
+require('templates/capsched/partials/labelCapacity');
+require('templates/components/editLabelCapacity');
+require('templates/components/confirmDiscardChanges');
+require('templates/components/saveConfigDialog');
+require('templates/components/labelCapacityBar');
+require('templates/components/displayRootLabel');
+require('templates/components/displayLeafLabel');

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 1eead4b..b75237f 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
@@ -21,7 +21,7 @@
     <span class="navbar-brand">Capacity Scheduler</span>
   </div>
 </nav>
-<div class="col-lg-12 capsched-container">
+<div class="capsched-container">
   <div class="col-lg-8">
     <ul class="nav nav-tabs">
       {{#link-to "capsched.scheduler" tagName="li"}}
@@ -38,7 +38,20 @@
       {{outlet}}
     </div>
   </div>
-  <div class="col-lg-4">
-    {{partial "versionsPanel"}}
-  </div>
 </div>
+<div class="col-lg-4 capsched-versions-wrapper">
+  {{partial "versionsPanel"}}
+</div>
+
+{{!-- ALERT --}}
+{{#if alertMessage}}
+  <div class="alert alert-danger">
+    <button {{action 'clearAlert'}} type="button" class="close" aria-hidden="false">&times;</button>
+    <strong> {{alertMessage.status}} </strong> {{alertMessage.simpleMessage}}
+    <div>
+      <small>{{alertMessage.message}}</small>
+    </div>
+    <br>
+    {{#link-to 'capsched.trace' class="alert-link"}}Trace{{/link-to}}
+  </div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 e54e14b..a9ef778 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
@@ -25,8 +25,13 @@
   {{/if}}
 </div>
 <div class="row">
-  <div class="btn btn-group-md col-md-offset-5">
-    <button type="button" {{bind-attr class=":btn :btn-default :btn-success isQueueMappingsDirty::disabled"}} name="saveAdvanced">Save</button>
-    <button type="button" {{bind-attr class=":btn :btn-default :btn-danger isQueueMappingsDirty::disabled"}} name="cancelAdvanced" {{action "rollbackQueueMappingProps"}}>Cancel</button>
+  <div class="btn btn-group-md col-md-offset-3">
+    <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 isQueueMappingsDirty::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>
   </div>
 </div>
+
+{{confirm-discard-changes isDialogOpen=isConfirmDialogOpen action="rollbackQueueMappingProps"}}
+
+{{save-config-dialog isDialogOpen=isSaveConfigDialogOpen configNote=configNote action="saveCapSchedConfigs" param=saveMode}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/editQueueCapacity.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/editQueueCapacity.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/editQueueCapacity.hbs
deleted file mode 100644
index 55910ee..0000000
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/editQueueCapacity.hbs
+++ /dev/null
@@ -1,58 +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.
-}}
-
-<div class="row form-inline">
-  <div class="col-md-2 col-sm-2">
-    <span class="queue-name">{{this.name}}</span>
-  </div>
-  <div class="col-md-5 col-md-5">
-    <div class="form-group input-group capacity-input-percent">
-      {{capacity-input class='input-sm' value=this.capacity queue=this maxVal=100}}
-      <span class="input-group-addon">%</span>
-    </div>
-    <div class="form-group capacity-input-slider">
-      {{input-range min="0" max="100" step="1" value=this.capacity class="input-sm"}}
-    </div>
-    {{#if view.isQueueCapacityDirty}}
-      <div class="btn-group btn-group-xs">
-        <a {{action 'rollbackProp' 'capacity' this}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
-      </div>
-    {{/if}}
-  </div>
-  <div class="col-md-5 col-sm-5">
-    <div {{bind-attr class=":form-group :input-group :capacity-input-percent view.isInvalidQueueMaximumCapacity:has-error"}}>
-      {{max-capacity-input class='input-sm' value=this.maximum_capacity queue=this maxVal=100}}
-      <span class="input-group-addon">%</span>
-    </div>
-    <div class="form-group capacity-input-slider">
-      {{input-range min="0" max="100" step="1" value=this.maximum_capacity class="input-sm"}}
-    </div>
-    {{#if view.isQueueMaximumCapacityDirty}}
-      <div class="btn-group btn-group-xs">
-        <a {{action 'rollbackProp' 'maximum_capacity' this}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
-      </div>
-    {{/if}}
-    {{#if view.isInvalidQueueMaximumCapacity}}
-      <div class="row">
-        <div class="col-md-12 col-sm-12">
-          <span class="text-danger">Maximum capacity must be greater than or equal to capacity</span>
-        </div>
-      </div>
-    {{/if}}
-  </div>
-</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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
new file mode 100644
index 0000000..e659f5c
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/partials/labelCapacity.hbs
@@ -0,0 +1,131 @@
+{{!
+* 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="label-capacity-container">
+  <div class="panel panel-default">
+    <div class="panel-heading">
+      <div class="panel-title">
+        Label Capacity <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>
+      </div>
+    </div>
+    <div id="collapsibleLabelCapacityPanel" {{bind-attr class=":panel-collapse :collapse view.isLabelsPanelCollapsed::in"}}>
+      <div class="panel-body">
+        {{#if isOperator}}
+          {{#if isNodeLabelsEnabledByRM}}
+            <div class="label-names">
+              <label>Accessible Node Labels: </label>
+              <span>{{accessibleLabelNames}}</span>
+            </div>
+            {{#if isRoot}}
+              <div class="border-wrapper">
+                <div class="row">
+                  <div class="col-sm-2 col-md-2">
+                    <label>Label</label>
+                  </div>
+                  <div class="col-sm-3 col-md-3">
+                    <label>Label Capacity</label>
+                  </div>
+                  <div class="col-sm-3 col-md-3">
+                    <label>Label Max Capacity</label>
+                  </div>
+                </div>
+                {{#if hasAnyNodeLabelsForQueue}}
+                  {{#each label in allLabelsForQueue}}
+                    {{display-root-label queueLabels=queueNodeLabels nonAccessibleLabels=nonAccessibleLabels label=label isRoot=isRoot}}
+                  {{/each}}
+                {{else}}
+                  <div class="row">
+                    <div class="col-md-12 col-sm-12">
+                      <small>No Node Labels Defined</small>
+                    </div>
+                  </div>
+                {{/if}}
+              </div>
+            {{/if}}
+            {{#if isLeafQ}}
+              {{#if hasQueueLabels}}
+                {{#each label in queueNodeLabels}}
+                  {{display-leaf-label label=label}}
+                {{/each}}
+              {{else}}
+                <div class="">
+                  <small>Node labels are not enabled. Goto parent queue to enable them.</small>
+                </div>
+              {{/if}}
+            {{else}}
+              {{#if hasChildrenQueueLabels}}
+                {{#each childQLabel in childrenQueueLabels}}
+                  <div class="border-wrapper">
+                    <div class="">
+                      <label>Label: </label>
+                      <span>{{childQLabel.labelName}}</span>
+                    </div>
+                    <div class="row">
+                      <div class="col-md-2 col-sm-2">
+                        <label>Children</label>
+                      </div>
+                      <div class="col-sm-4 col-md-4">
+                        <label>Label Capacity</label>
+                      </div>
+                      <div class="col-sm-4 col-md-4">
+                        <label>Label Max Capacity</label>
+                      </div>
+                    </div>
+                    {{#each row in childQLabel.childrenQueueLabels}}
+                      {{edit-label-capacity label=row.label queue=row.queue parentQueue=row.parentQueue}}
+                    {{/each}}
+
+                    {{label-capacity-bar queueLabels=childQLabel.childrenQueueLabels}}
+                  </div>
+                {{/each}}
+              {{else}}
+                <div class="">
+                  <small>Node labels are not enabled. Goto parent queue to enable them.</small>
+                </div>
+              {{/if}}
+            {{/if}}
+          {{else}}
+            <div>
+              <small>Node labels are disabled by RM. Configure and enable labels to map the labels to queues.</small>
+            </div>
+          {{/if}}
+        {{else}}
+          {{#if isNodeLabelsEnabledByRM}}
+            <div class="label-names">
+              <label>Accessible Node Labels: </label>
+              <span>{{accessibleLabelNames}}</span>
+            </div>
+            {{#if hasQueueLabels}}
+              {{#each label in queueNodeLabels}}
+                {{display-leaf-label label=label}}
+              {{/each}}
+            {{else}}
+              <div class="">
+                <small>Node labels are not enabled</small>
+              </div>
+            {{/if}}
+          {{else}}
+            <div>
+              <small>Node labels are disabled</small>
+            </div>
+          {{/if}}
+        {{/if}}
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 ee9616b..b4891cd 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
@@ -45,7 +45,7 @@
               </div>
             </div>
             {{#each childQ in childrenQueues}}
-              {{render "capsched/partials/editQueueCapacity" childQ}}
+              {{edit-queue-capacity queue=childQ warnInvalidTotalCapacity=warnInvalidCapacity}}
             {{/each}}
             <div class="row">
               <div class="col-md-2 col-sm-2">

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 b81474e..b1a8708 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
@@ -79,32 +79,17 @@
   </div>
   {{#if isOperator}}
     <div class="btn btn-group-sm col-sm-offset-2">
-      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled needSave::disabled"}} name="saveOnly" {{action "showSaveConfigDialog" target="view"}}>Save Only</button>
-      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled needRefresh::disabled"}} name="saveAndRefresh" {{action "showSaveConfigDialog" "refresh" target="view"}}>Save And Refresh Queues</button>
-      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled needRestart::disabled"}} name="saveAndRestart" {{action "showSaveConfigDialog" "restart" target="view"}}>Save And Restart RM</button>
-      <button type="button" {{bind-attr class=":btn :btn-danger isAnyQueueDirty::disabled"}} name="cancelQueuesconfBtn" {{action "cancelQueuesChanges"}}>Cancel Changes</button>
+      <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 needRefresh::disabled"}} name="saveAndRefresh" {{action "showSaveConfigDialog" "refresh"}}>Save And Refresh Queues</button>
+      <button type="button" {{bind-attr class=":btn :btn-success canNotSave:disabled needRestart::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>
     </div>
   {{/if}}
 </div>
 
-{{!-- CONFIG NOTE MODAL --}}
-<div class="modal fade" id="configNoteModalDialog" tabindex="-1" role="dialog" aria-labelledby="noteConfigModalLabel" aria-hidden="true">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
-        <h4 class="modal-title" id="noteConfigModalLabel">Notes</h4>
-      </div>
-      <div class="modal-body">
-        {{textarea class="form-control" rows="3" style="max-width: 100%;" placeholder="What did you change?" value=configNote}}
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-        <button {{action 'saveQueuesConfig' view.saveMode}} type="button" class="btn btn-success" data-dismiss="modal">Save Changes</button>
-      </div>
-    </div>
-  </div>
-</div>
+{{save-config-dialog isDialogOpen=isSaveConfigDialogOpen configNote=configNote action="saveCapSchedConfigs" param=saveMode}}
+
+{{confirm-discard-changes isDialogOpen=isConfirmDialogOpen action="discardQueuesChanges"}}
 
 {{!-- DELETE QUEUE CONFIRM MODAL --}}
 <div class="modal fade" id="deleteQueueModalDialog" tabindex="-1" role="dialog" aria-labelledby="deleteQModalLabel" aria-hidden="true">
@@ -112,7 +97,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
-        <h4 class="modal-title" id="deleteQModalLabel">Confirm?</h4>
+        <h4 class="modal-title" id="deleteQModalLabel">Confirm</h4>
       </div>
       <div class="modal-body">
         <span>Are you sure you want to delete the queue?</span>
@@ -124,16 +109,3 @@
     </div>
   </div>
 </div>
-
-{{!-- ALERT --}}
-{{#if alertMessage}}
-  <div class="alert alert-danger">
-    <button {{action 'clearAlert'}} type="button" class="close" aria-hidden="true">&times;</button>
-    <strong> {{alertMessage.status}} </strong> {{alertMessage.simpleMessage}}
-    <div>
-      <small>{{alertMessage.message}}</small>
-    </div>
-    <br>
-    {{#link-to 'capsched.trace' class="alert-link"}}Trace{{/link-to}}
-  </div>
-{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf/editqueue.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf/editqueue.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf/editqueue.hbs
index aad16c2..2848fed 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf/editqueue.hbs
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/capsched/queuesconf/editqueue.hbs
@@ -64,6 +64,10 @@
     {{partial "capsched/partials/queueCapacity"}}
   </div>
 
+  <div class="label-capacity-wrapper">
+    {{partial "capsched/partials/labelCapacity"}}
+  </div>
+
   <div class="queue-acl-wrapper">
     {{partial "capsched/partials/accessControlList"}}
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/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 f11b786..7649512 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
@@ -118,7 +118,7 @@
             }}
             {{#if schedulerDirtyFilelds.resource_calculator}}
               <div class="btn-group btn-group-xs">
-                  <a {{action 'rollbackProp' 'resource_calculator' scheduler}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
+                <a {{action 'rollbackProp' 'resource_calculator' scheduler}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
               </div>
             {{/if}}
           </div>
@@ -129,9 +129,14 @@
 </div>
 {{#if isOperator}}
   <div class="row">
-    <div class="btn btn-group-md col-md-offset-5">
-      <button type="button" {{bind-attr class=":btn :btn-default :btn-success isSchedulerDirty::disabled"}} name="saveAdvanced">Save</button>
-      <button type="button" {{bind-attr class=":btn :btn-default :btn-danger isSchedulerDirty::disabled"}} name="cancelAdvanced" {{action 'rollbackSchedulerProps'}}>Cancel</button>
+    <div class="btn btn-group-md col-md-offset-3">
+      <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 isSchedulerDirty::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>
     </div>
   </div>
 {{/if}}
+
+{{confirm-discard-changes isDialogOpen=isConfirmDialogOpen action="rollbackSchedulerProps"}}
+
+{{save-config-dialog isDialogOpen=isSaveConfigDialogOpen configNote=configNote action="saveCapSchedConfigs" param=saveMode}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/confirmDiscardChanges.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/confirmDiscardChanges.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/confirmDiscardChanges.hbs
new file mode 100644
index 0000000..5845f8b
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/confirmDiscardChanges.hbs
@@ -0,0 +1,36 @@
+{{!
+* 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.
+}}
+
+{{!-- DISCARD CHANGES CONFIRM MODAL DIALOG --}}
+<div class="modal fade" id="confirmDiscardChangesDialog" tabindex="-1" role="dialog" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
+        <h4 class="modal-title">Confirm</h4>
+      </div>
+      <div class="modal-body">
+        <p>Are you sure you want to discard the changes?</p>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal" {{action "cancel"}}>No</button>
+        <button type="button" class="btn btn-success" data-dismiss="modal" {{action "okay"}}>Yes</button>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayLeafLabel.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayLeafLabel.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayLeafLabel.hbs
new file mode 100644
index 0000000..859423b
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayLeafLabel.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="border-wrapper">
+  <div class="">
+    <label>Label: </label>
+    <span>{{label.name}}</span>
+  </div>
+  {{#if label.isNotExist}}
+    <div class="col-md-10 col-sm-10 text-warning">
+      {{#if label.store.isRmOffline}}
+        <small>Unable to obtain information about the node label from the resource manager</small>
+      {{else}}
+        <small>Label does not exist on cluster</small>
+      {{/if}}
+    </div>
+  {{else}}
+    <div class="row">
+      <div class="col-sm-5 col-md-5">
+        <label>Label Capacity: </label>
+        <span>{{label.capacity}}%</span>
+      </div>
+      <div class="col-sm-5 col-md-5">
+        <label>Label Max Capacity: </label>
+        <span>{{label.maximum_capacity}}%</span>
+      </div>
+    </div>
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayRootLabel.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayRootLabel.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayRootLabel.hbs
new file mode 100644
index 0000000..761ab00
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/displayRootLabel.hbs
@@ -0,0 +1,51 @@
+{{!
+* 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="row node-label-item">
+  <div class="col-md-2 col-sm-2">
+    <span>{{label.name}}</span>
+  </div>
+  {{#if label.isNotExist}}
+    <div class="col-md-10 col-sm-10 text-warning">
+      {{#if label.store.isRmOffline}}
+        <small>Unable to obtain information about the node label from the resource manager</small>
+      {{else}}
+        <small>Label does not exist on cluster</small>
+      {{/if}}
+    </div>
+  {{else}}
+    <div class="col-sm-3 col-md-3">
+      <span>{{label.capacity}}%</span>
+    </div>
+    <div class="col-sm-3 col-md-3">
+      <span>{{label.maximum_capacity}}%</span>
+    </div>
+    <div class="col-sm-2 col-md-2">
+      <span></span>
+    </div>
+    {{#if isRoot}}
+      <div class="col-sm-2 col-md-2">
+        {{#if isAccessEnabled}}
+          <button type="button" class="btn btn-small btn-danger" {{action "disableRootLabel" label}}>Disable Access</button>
+        {{else}}
+          <button type="button" class="btn btn-small btn-primary" {{action "enableRootLabel" label}}>Enable Access</button>
+        {{/if}}
+      </div>
+    {{/if}}
+  {{/if}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8f5f2c66/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/editLabelCapacity.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/editLabelCapacity.hbs b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/editLabelCapacity.hbs
new file mode 100644
index 0000000..9e25cc6
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/templates/components/editLabelCapacity.hbs
@@ -0,0 +1,73 @@
+{{!
+* 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="row form-inline node-label-item">
+  {{#if label.isNotExist}}
+    <div class="col-md-12 col-sm-12 text-warning">
+      {{#if label.store.isRmOffline}}
+        <small>Unable to obtain information about the node label from the resource manager</small>
+      {{else}}
+        <small>Label does not exist on cluster</small>
+      {{/if}}
+    </div>
+  {{else}}
+    <div class="col-md-2 col-sm-2">
+      {{#link-to 'capsched.queuesconf.editqueue' queue}}{{queue.name}}{{/link-to}}
+    </div>
+    <div class="col-md-4 col-sm-4">
+      <div class="form-group input-group label-capacity-input">
+        {{capacity-input class='input-sm' value=label.capacity maxVal=100 disabled=isAccessDisabled}}
+        <span class="input-group-addon">%</span>
+      </div>
+      <div class="form-group label-capacity-slider">
+        {{input-range min="0" max="100" step="1" value=label.capacity class="input-sm"}}
+      </div>
+      {{#if isLabelCapacityDirty}}
+        <div class="btn-group btn-group-xs label-capacity-rollback">
+          <a {{action 'rollbackProp' 'capacity' label}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
+        </div>
+      {{/if}}
+    </div>
+    <div class="col-md-4 col-sm-4">
+      <div {{bind-attr class=":form-group :input-group :label-capacity-input isInvalidLabelMaxCapacity:has-error"}}>
+        {{max-capacity-input class='input-sm' value=label.maximum_capacity maxVal=100 disabled=isAccessDisabled}}
+        <span class="input-group-addon">%</span>
+      </div>
+      <div class="form-group label-capacity-slider">
+        {{input-range min="0" max="100" step="1" value=label.maximum_capacity class="input-sm"}}
+      </div>
+      {{#if isLabelMaxCapacityDirty}}
+        <div class="btn-group btn-group-xs label-capacity-rollback">
+          <a {{action 'rollbackProp' 'maximum_capacity' label}} href="#" class="btn btn-default btn-warning"><i class="fa fa-undo"></i></a>
+        </div>
+      {{/if}}
+      {{#if isInvalidLabelMaxCapacity}}
+        <div class="label-maxcapacity-error">
+          <span class="text-danger">Maximum capacity must be greater than or equal to capacity</span>
+        </div>
+      {{/if}}
+    </div>
+    <div class="col-md-2 col-sml-2">
+      {{#if isAccessEnabled}}
+        <button type="button" class="btn btn-small btn-danger" {{action "disableAccess"}}>Disable Access</button>
+      {{else}}
+        <button type="button" class="btn btn-small btn-primary" {{action "enableAccess"}} {{bind-attr disabled=isDisabledByParent}}>Enable Access</button>
+      {{/if}}
+    </div>
+  {{/if}}
+</div>


Mime
View raw message