ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pallav...@apache.org
Subject ambari git commit: AMBARI-16842. Capacity Scheduler View - Save only, Save and Restart Rm and Delete queue integrations (Akhil PB via pallavkul)
Date Tue, 07 Jun 2016 11:59:19 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk bce6052c9 -> a6574055a


AMBARI-16842. Capacity Scheduler View - Save only, Save and Restart Rm and Delete queue integrations
(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/a6574055
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a6574055
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a6574055

Branch: refs/heads/trunk
Commit: a6574055a9f1da87b4d2c9ad320171f71f7d58f0
Parents: bce6052
Author: Pallav Kulshreshtha <pallav.kul@gmail.com>
Authored: Tue Jun 7 17:28:21 2016 +0530
Committer: Pallav Kulshreshtha <pallav.kul@gmail.com>
Committed: Tue Jun 7 17:28:21 2016 +0530

----------------------------------------------------------------------
 .../resources/ui/app/components/queueBadge.js   |  15 +-
 .../resources/ui/app/components/queueSummary.js |  23 +-
 .../resources/ui/app/controllers/editqueue.js   |  20 +-
 .../resources/ui/app/controllers/queuesconf.js  | 268 ++++++++++++++++---
 .../src/main/resources/ui/app/models/queue.js   |   3 +-
 .../resources/ui/app/styles/application.less    |   4 +
 .../ui/app/templates/capsched/queuesconf.hbs    |  57 ++--
 .../ui/app/templates/capsched/scheduler.hbs     |  12 +-
 .../app/templates/components/queueSummary.hbs   |  25 +-
 .../resources/ui/app/views/editQueueCapacity.js |   4 +-
 .../main/resources/ui/app/views/queuesconf.js   |  11 +-
 11 files changed, 362 insertions(+), 80 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 1e2b77c..f8978c2 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
@@ -30,6 +30,19 @@ App.WarnBadgeComponent = Em.Component.extend({
   }.on('didInsertElement'),
 });
 
+App.WarningInfoComponent = Em.Component.extend({
+  layout:Em.Handlebars.compile('<i class="fa fa-fw fa-lg fa-warning"></i>'),
+  tagName:'span',
+  tooltip:'Warning',
+  initTooltip: function(){
+    var tipMsg = this.get('tooltip');
+    this.$().tooltip({
+      title:tipMsg,
+      placement:'bottom'
+    });
+  }.on('didInsertElement'),
+});
+
 App.QueueBadgeComponent = Em.Component.extend({
   layoutName:'components/queueBadge',
   tagName:'span',
@@ -92,4 +105,4 @@ App.QueueBadgeComponent = Em.Component.extend({
 
     return icon;
   }.property('q.isNewQueue','q.isSaving','q.isError','q.isAnyDirty','q.isDeletedQueue')
-});
\ No newline at end of file
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 3d4f7be..113ad13 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
@@ -21,6 +21,8 @@
  var _runState = 'RUNNING';
  var _stopState = 'STOPPED';
 
+ var _notStartedState = 'NOT STARTED';
+
  App.QueueSummaryComponent = Ember.Component.extend({
    layoutName: 'components/queueSummary',
    queue: null,
@@ -31,13 +33,29 @@
    }.property('queue.state'),
 
    queueState: function() {
-     if (this.get('isRunningState')) {
+     if (this.get('queue.isNewQueue')) {
+       return _notStartedState;
+     } else if (this.get('isRunningState')) {
        return _runState;
      } else {
        return _stopState;
      }
    }.property('queue.state'),
 
+   qStateColor: function() {
+     if (this.get('queue.isNewQueue')) {
+       return 'text-info';
+     } else if (this.get('isRunningState')) {
+       return 'text-success';
+     } else {
+       return 'text-danger';
+     }
+   }.property('queue.state'),
+
+   isDirtyState: function() {
+     return this.get('queue').changedAttributes().hasOwnProperty('state');
+   }.property('queue.state'),
+
    effectiveCapacity: function() {
      var currentQ = this.get('queue'),
      allQueues = this.get('allQueues'),
@@ -46,7 +64,8 @@
        effectiveCapacityRatio *= (currentQ.get('capacity') / 100);
        currentQ = allQueues.findBy('id', currentQ.get('parentPath').toLowerCase()) || null;
      }
-     var effectiveCapacityPercent = Math.round(effectiveCapacityRatio * 100);
+     var effectiveCapacityPercent = effectiveCapacityRatio * 100;
+     this.get('queue').set('absolute_capacity', effectiveCapacityPercent || null);
      return effectiveCapacityPercent;
    }.property('queue.capacity', 'allQueues.@each.capacity', 'allQueues.length')
  });

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 e981ea5..518b677 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
@@ -165,8 +165,14 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
          this.set('content.maximum_applications', null);
        }
      }
-     return this.get('content.maximum_applications') || this.get('scheduler.maximum_applications');
-   }.property('content.maximum_applications', 'scheduler.maximum_applications'),
+     var schedulerMaxApps = this.get('scheduler.maximum_applications'),
+     absoluteCapacity = this.get('content.absolute_capacity');
+     if (this.get('content.maximum_applications')) {
+       return this.get('content.maximum_applications');
+     } else {
+       return Math.round(schedulerMaxApps * (absoluteCapacity / 100));
+     }
+   }.property('content.maximum_applications', 'content.absolute_capacity', 'scheduler.maximum_applications'),
 
    /**
     * Returns maximum AM resource percent for a queue if defined,
@@ -180,8 +186,14 @@ App.CapschedQueuesconfEditqueueController = Ember.Controller.extend({
          this.set('content.maximum_am_resource_percent', null);
        }
      }
-     return this.get('content.maximum_am_resource_percent') || this.get('scheduler.maximum_am_resource_percent');
-   }.property('content.maximum_am_resource_percent', 'scheduler.maximum_am_resource_percent'),
+     var schedulerResoucePercent = this.get('scheduler.maximum_am_resource_percent'),
+     absoluteCapacity = this.get('content.absolute_capacity');
+     if (this.get('content.maximum_am_resource_percent')) {
+        return this.get('content.maximum_am_resource_percent')
+     } else {
+       return (schedulerResoucePercent * (absoluteCapacity / 100));
+     }
+   }.property('content.maximum_am_resource_percent', 'content.absolute_capacity', 'scheduler.maximum_am_resource_percent'),
 
    /**
     * Sets ACL value to '*' or ' ' and returns '*' and 'custom' respectively.

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 14ea85c..93f6645 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
@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+
 var _runState = 'RUNNING';
 var _stopState = 'STOPPED';
 
@@ -39,58 +40,61 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
       parentPath = this.get('selectedQueue.path'),
       queuePath = [parentPath, queueName].join('.'),
       depth = parentPath.split('.').length,
-      queueAlreadyExists = store.hasRecordForId('queue', queuePath.toLowerCase()),
       leafQueueNames = store.getById('queue', parentPath.toLowerCase()).get('queuesArray'),
       newInLeaf = Ember.isEmpty(leafQueueNames),
-      existed = store.get('deletedQueues').findBy('path', queuePath),
       totalLeafCapacity,
       freeLeafCapacity,
       newQueue;
 
       this.send('clearCreateQueue');
-
-      if (existed) {
-        newQueue = store.createFromDeleted(existed);
-      } else {
-        if (!newInLeaf) {
-          totalLeafCapacity = leafQueueNames.reduce(function (capacity, qName) {
-            return store.getById('queue', [parentPath, qName].join('.').toLowerCase()).get('capacity')
+ capacity;
-          }, 0);
-          freeLeafCapacity = (totalLeafCapacity < 100) ? 100 - totalLeafCapacity : 0;
-        }
-
-        var qCapacity = (newInLeaf) ? 100 : freeLeafCapacity;
-
-        newQueue = store.createRecord('queue', {
-          id: queuePath,
-          name: queueName,
-          path: queuePath,
-          parentPath: parentPath,
-          depth: depth,
-          isNewQueue: true,
-          capacity: qCapacity,
-          maximum_capacity: qCapacity
-        });
-
-        this.set('newQueue', newQueue);
+      if (!newInLeaf) {
+        totalLeafCapacity = leafQueueNames.reduce(function (capacity, qName) {
+          return store.getById('queue', [parentPath, qName].join('.').toLowerCase()).get('capacity')
+ capacity;
+        }, 0);
+        freeLeafCapacity = (totalLeafCapacity < 100) ? 100 - totalLeafCapacity : 0;
       }
-
+      var qCapacity = (newInLeaf) ? 100 : freeLeafCapacity;
+      newQueue = store.createRecord('queue', {
+        id: queuePath.toLowerCase(),
+        name: queueName,
+        path: queuePath,
+        parentPath: parentPath,
+        depth: depth,
+        isNewQueue: true,
+        capacity: qCapacity,
+        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() {
+    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'),
-      opt = 'saveAndRefresh',
-      saveQs = this.get('queues').save();
+      optn = '',
+      saveQs = this.get('queues').save(),
+      labels = DS.ManyArray.create({content:collectedLabels}).save();
 
-      Ember.RSVP.Promise.all([saveQs]).then(
-        Em.run.bind(this, 'saveQueuesConfigSuccess'),
-        Em.run.bind(this, 'saveQueuesConfigError', opt)
-      ).then(function() {
-        return store.relaunchCapSched(opt);
-      }).catch(Em.run.bind(this, 'saveQueuesConfigError', opt));
+      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));
     },
     clearCreateQueue: function() {
       this.set('newQueueName', '');
@@ -100,9 +104,33 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     },
     clearAlert: function () {
       this.set('alertMessage', null);
+    },
+    cancelQueuesChanges: function() {
+
+    },
+    stopQueue: function() {
+      this.set('selectedQueue.state', _stopState);
+    },
+    startQueue: function() {
+      this.set('selectedQueue.state', _runState);
+    },
+    deleteQueue: function() {
+      var that = this;
+      var delQ = this.get('selectedQueue');
+      if (delQ.get('isNew')) {
+        this.set('newQueue', null);
+      }
+      this.transitionToRoute('capsched.queuesconf.editqueue', delQ.get('parentPath').toLowerCase())
+      .then(Em.run.schedule('afterRender', function () {
+        that.get('store').recurceRemoveQueue(delQ);
+      }));
     }
   },
 
+  isAnyQueueDirty: function() {
+    return this.get('queues').isAny('isAnyDirty');
+  }.property('queues.@each.isAnyDirty'),
+
   selectedQueue: null,
   newQueue: null,
   newQueueName: '',
@@ -115,6 +143,7 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
     queueName = this.get('newQueueName'),
     queuePath = [parentPath, queueName].join('.'),
     qAlreadyExists = this.store.hasRecordForId('queue', queuePath.toLowerCase());
+
     if (Ember.isBlank(queueName)) {
       this.set('isInvalidQueueName', true);
       this.set('invalidQueueNameMessage', 'Enter queue name');
@@ -133,25 +162,185 @@ App.CapschedQueuesconfController = Ember.Controller.extend({
   }.observes('newQueueName', 'newQueueName.length'),
 
   /**
+   * Marks each queue in leaf with 'overCapacity' if sum if their capacity values is greater
than 100.
+   * @method capacityControl
+   */
+  capacityControl: function() {
+    var paths = this.get('queues').getEach('parentPath').uniq();
+    paths.forEach(function (path) {
+      var leaf = this.get('queues').filterBy('parentPath', path),
+      total = leaf.reduce(function (prev, queue) {
+          return +queue.get('capacity') + prev;
+        }, 0);
+      leaf.setEach('overCapacity', total != 100);
+    }.bind(this));
+  }.observes('queues.length','queues.@each.capacity'),
+
+  /**
    * True if newQueue is not empty.
    * @type {Boolean}
    */
   hasNewQueue: Ember.computed.bool('newQueue'),
 
   /**
+   * True if some queue of desired configs was removed.
+   * @type {Boolean}
+   */
+  hasDeletedQueues: Ember.computed.alias('store.hasDeletedQueues'),
+
+  /**
+   * Check properties for refresh requirement
+   * @type {Boolean}
+   */
+  needRefreshProps: Ember.computed.any('hasChanges', 'hasNewQueues'),
+
+  /**
+   * List of modified queues.
+   * @type {Array}
+   */
+  dirtyQueues:function () {
+    return this.get('queues').filter(function (q) {
+      return q.get('isAnyDirty');
+    });
+  }.property('queues.@each.isAnyDirty'),
+
+  /**
+   * True if dirtyQueues is not empty.
+   * @type {Boolean}
+   */
+  hasChanges: Ember.computed.notEmpty('dirtyQueues.[]'),
+
+  /**
+   * List of new queues.
+   * @type {Array}
+   */
+  newQueues: Ember.computed.filterBy('queues', 'isNewQueue', true),
+
+  /**
+   * True if newQueues is not empty.
+   * @type {Boolean}
+   */
+  hasNewQueues: Ember.computed.notEmpty('newQueues.[]'),
+
+  /**
+   * check if RM needs restart
+   * @type {bool}
+   */
+  needRestart: Em.computed.and('hasDeletedQueues', 'isOperator'),
+
+  /**
+   * check there is some changes for save
+   * @type {bool}
+   */
+  needSave: Em.computed.any('needRestart', 'needRefresh'),
+
+  /**
+   * check if RM needs refresh
+   * @type {bool}
+   */
+  needRefresh: Em.computed.and('needRefreshProps', 'noNeedRestart', 'isOperator'),
+
+  /**
+   * Inverted needRestart value.
+   * @type {Boolean}
+   */
+  noNeedRestart: Em.computed.not('needRestart'),
+
+  /**
+   * check if can save configs
+   * @type {bool}
+   */
+  canNotSave: Em.computed.any('hasOverCapacity', 'hasInvalidMaxCapacity', 'hasUncompetedAddings',
'hasNotValid', 'hasNotValidLabels'),
+
+  /**
+   * List of not valid queues.
+   * @type {Array}
+   */
+  notValid: Em.computed.filterBy('queues', 'isValid', false),
+
+  /**
+   * True if notValid is not empty.
+   * @type {Boolean}
+   */
+  hasNotValid: Em.computed.notEmpty('notValid.[]'),
+
+  /**
+   * True if queues have not valid labels.
+   * @type {Boolean}
+   */
+  hasNotValidLabels: function() {
+    return this.get('queues').anyBy('hasNotValidLabels',true);
+  }.property('queues.@each.hasNotValidLabels'),
+
+  /**
+   * List of queues with excess of capacity
+   * @type {Array}
+   */
+  overCapacityQ: function () {
+    return this.get('queues').filter(function (q) {
+      return q.get('overCapacity');
+    });
+  }.property('queues.@each.overCapacity'),
+
+  /**
+   * True if overCapacityQ is not empty.
+   * @type {Boolean}
+   */
+  hasOverCapacity: Em.computed.notEmpty('overCapacityQ.[]'),
+
+  /**
+   * True if any queue has invalid max capacity (if max_cappacity < capacity).
+   * @type {Boolean}
+   */
+  hasInvalidMaxCapacity: Em.computed.filterBy('queues', 'isInvalidMaxCapacity', true),
+
+  /**
+   * List of queues with incomplete adding process
+   * @type {[type]}
+   */
+  uncompetedAddings: Em.computed.filterBy('queues', 'isNew', true),
+
+  /**
+   * True if uncompetedAddings is not empty.
+   * @type {Boolean}
+   */
+  hasUncompetedAddings: Em.computed.notEmpty('uncompetedAddings.[]'),
+
+  /**
    * Represents queue run state. Returns true if state is null.
    * @return {Boolean}
    */
   isSelectedQRunning: function() {
-    return this.get('selectedQueue.state') == _runState || this.get('selectedQueue.state')
== null;
+    if (!this.get('selectedQueue.isNewQueue')) {
+      return this.get('selectedQueue.state') === _runState || this.get('selectedQueue.state')
=== null;
+    } else {
+      return false;
+    }
+  }.property('selectedQueue.state', 'selectedQueue.isNewQueue'),
+
+  isSelectedQStopped: function() {
+    return this.get('selectedQueue.state') === _stopState;
   }.property('selectedQueue.state'),
 
+
+  isSelectedQLeaf: function() {
+    return this.get('selectedQueue.queues') === null;
+  }.property('selectedQueue.queues'),
+
+  isSelectedQLeafAndRunning: function() {
+    return this.get('isSelectedQLeaf') && this.get('isSelectedQRunning');
+  }.property('isSelectedQRunning', 'isSelectedQLeaf'),
+
   /**
    * Returns true if queue is root.
    * @type {Boolean}
    */
    isRootQSelected: Ember.computed.match('selectedQueue.id', /^(root)$/),
 
+   isSelectedQDeletable: function() {
+     return !this.get('isRootQSelected') && !this.get('isSelectedQRunning');
+   }.property('isRootQSelected', 'isSelectedQRunning'),
+
    /**
     * Property for error message which may appear when saving queue.
     * @type {Object}
@@ -176,5 +365,8 @@ 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/a6574055/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 46f14ad..45146ef 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
@@ -210,6 +210,8 @@ App.Queue = DS.Model.extend({
     return this.get('_overCapacity') || !Em.isEmpty(this.get('labels').filterBy('overCapacity'));
   }.property('_overCapacity','labels.@each.overCapacity'),
 
+  isInvalidMaxCapacity: false,
+
   //new queue flag
   isNewQueue:DS.attr('boolean', {defaultValue: false}),
 
@@ -244,4 +246,3 @@ App.Queue = DS.Model.extend({
     }
   }.observes('labels','default_node_label_expression')
 });
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 89b8eb7..9952045 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
@@ -1175,3 +1175,7 @@
     border-bottom-color: #a94442 !important;
   }
 }
+
+.yellow-warning {
+  color: #f0ad4e;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 3837a03..b81474e 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
@@ -28,24 +28,28 @@
             {{#if selectedQueue}}
               <div class="queue-actions-wrapper">
                 <div class="pull-left">
-                  <button type="button" class="btn btn-primary btn-xs" name="addQueueBtn"
{{action "addNewQueue"}}>Add Queue</button>
+                  <button type="button" {{bind-attr class=":btn :btn-primary :btn-xs isSelectedQLeafAndRunning:disabled"}}
name="addQueueBtn" {{action "addNewQueue"}}>Add Queue</button>
                 </div>
                 <div class="pull-right">
-                    {{#unless isRootQSelected}}
-                      <button type="button" class="btn btn-danger btn-xs" name="deleteQueueBtn">Delete</button>
+                  {{#if isSelectedQRunning}}
+                    <button type="button" class="btn btn-primary btn-xs" name="queueStateBtn"
{{action "stopQueue"}}>Stop Queue</button>
+                  {{/if}}
+                  {{#if isSelectedQStopped}}
+                    <button type="button" class="btn btn-primary btn-xs" name="queueStateBtn"
{{action "startQueue"}}>Start Queue</button>
+                  {{/if}}
+                  {{#unless isRootQSelected}}
+                    <button type="button" {{bind-attr class=":btn :btn-danger :btn-xs
isSelectedQDeletable::disabled"}} class="btn btn-danger btn-xs" name="deleteQueueBtn" {{action
"showDeleteQueueDialog" target="view"}}>Delete Queue</button>
+                    {{#unless isSelectedQDeletable}}
+                      {{warning-info class="yellow-warning" tooltip="Queue should be STOPPED
to delete"}}
                     {{/unless}}
-                    {{#if isSelectedQRunning}}
-                      <button type="button" class="btn btn-warning btn-xs" name="queueStateBtn">Stop
Queue</button>
-                    {{else}}
-                      <button type="button" class="btn btn-primary btn-xs" name="queueStateBtn">Start
Queue</button>
-                    {{/if}}
+                  {{/unless}}
                 </div>
               </div>
               {{#if showQueueNameInput}}
                 <div {{bind-attr class=":add-newqueuename-wrapper isInvalidQueueName:has-error"}}
class="add-newqueuename-wrapper">
                   {{input type="text" name="addNewQueueName" class="form-control input-sm
new-queue-name" value=newQueueName placeholder="Enter queue name..."}}
                   <div class="btn-group btn-group-sm pull-right">
-                    <button type="button" class="btn btn-primary" name="createNewQueueBtn"
{{action "createNewQueue"}}>Create</button>
+                    <button type="button" class="btn btn-primary" name="createNewQueueBtn"
{{action "createNewQueue"}} {{bind-attr disabled=isInvalidQueueName}}>Create</button>
                     <button type="button" class="btn btn-default" name="cancelNewQueueBtn"
{{action "clearCreateQueue"}}>Cancel</button>
                   </div>
                   {{#if isInvalidQueueName}}
@@ -73,12 +77,14 @@
       </div>
     </div>
   </div>
-  <div class="btn btn-group-sm col-sm-offset-2">
-    <button type="button" class="btn btn-success" name="saveOnly">Save Only</button>
-    <button type="button" class="btn btn-success" name="saveAndRefresh" {{action "showSaveConfigDialog"
target="view"}}>Save And Refresh Queues</button>
-    <button type="button" class="btn btn-warning" name="saveAndRestart">Save And Restart
RM</button>
-    <button type="button" class="btn btn-danger" name="cancelQueuesconfBtn">Cancel
Changes</button>
-  </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>
+    </div>
+  {{/if}}
 </div>
 
 {{!-- CONFIG NOTE MODAL --}}
@@ -94,7 +100,26 @@
       </div>
       <div class="modal-footer">
         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
-        <button {{action 'saveQueuesConfig'}} type="button" class="btn btn-success" data-dismiss="modal">Save
Changes</button>
+        <button {{action 'saveQueuesConfig' view.saveMode}} type="button" class="btn btn-success"
data-dismiss="modal">Save Changes</button>
+      </div>
+    </div>
+  </div>
+</div>
+
+{{!-- DELETE QUEUE CONFIRM MODAL --}}
+<div class="modal fade" id="deleteQueueModalDialog" tabindex="-1" role="dialog" aria-labelledby="deleteQModalLabel"
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="deleteQModalLabel">Confirm?</h4>
+      </div>
+      <div class="modal-body">
+        <span>Are you sure you want to delete the queue?</span>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">No</button>
+        <button type="button" class="btn btn-success" data-dismiss="modal" {{action "deleteQueue"}}>Yes</button>
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 364bff2..f11b786 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
@@ -127,9 +127,11 @@
     </div>
   </div>
 </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 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>
+{{#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>
   </div>
-</div>
+{{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/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 7ba9e62..ef5663d 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
@@ -21,43 +21,46 @@
     <div class="panel panel-default">
       <div class="panel-body">
         <div class="row">
-          <div class="col-sm-6">
+          <div class="col-sm-5">
             <label>Name</label>
           </div>
-          <div class="col-sm-4">
+          <div class="col-sm-6">
             <span>{{queue.name}}</span>
           </div>
         </div>
         <div class="row">
-          <div class="col-sm-6">
+          <div class="col-sm-5">
             <label>Path</label>
           </div>
-          <div class="col-sm-4">
+          <div class="col-sm-6">
             <span>{{queue.path}}</span>
           </div>
         </div>
         <div class="row">
-          <div class="col-sm-6">
+          <div class="col-sm-5">
             <label>Capacity</label>
           </div>
-          <div class="col-sm-4">
+          <div class="col-sm-5">
             <span>{{queue.capacity}}%</span>
           </div>
         </div>
         <div class="row">
-          <div class="col-sm-6">
+          <div class="col-sm-5">
             <label>Absolute Capacity</label>
           </div>
-          <div class="col-sm-4">
+          <div class="col-sm-5">
             <span>{{effectiveCapacity}}%</span>
           </div>
         </div>
         <div class="row">
-          <div class="col-sm-6">
+          <div class="col-sm-5">
             <label>State</label>
           </div>
-          <div class="col-sm-4">
-            <span {{bind-attr class="isRunningState:text-success:text-danger"}}>{{queueState}}</span>
+          <div class="col-sm-6">
+            <span {{bind-attr class="qStateColor"}}>{{queueState}}</span>
+            {{#if isDirtyState}}
+              {{warning-info class="yellow-warning" tooltip="Not Yet Saved"}}
+            {{/if}}
           </div>
         </div>
       </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/editQueueCapacity.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/editQueueCapacity.js
b/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/editQueueCapacity.js
index 5c3793f..b2ae1d5 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/editQueueCapacity.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/editQueueCapacity.js
@@ -28,6 +28,8 @@ App.CapschedPartialsEditQueueCapacityView = Ember.View.extend({
   }.property('controller.content.maximum_capacity'),
 
   isInvalidQueueMaximumCapacity: function() {
-    return this.get('controller.content.maximum_capacity') < this.get('controller.content.capacity');
+    var isInvalid = this.get('controller.content.maximum_capacity') < this.get('controller.content.capacity');
+    this.set('controller.content.isInvalidMaxCapacity', isInvalid);
+    return isInvalid;
   }.property('controller.content.capacity', 'controller.content.maximum_capacity')
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/a6574055/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/queuesconf.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/queuesconf.js
b/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/queuesconf.js
index 7cb71a7..5cef8e5 100644
--- a/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/queuesconf.js
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/views/queuesconf.js
@@ -19,9 +19,18 @@
 var App = require('app');
 
 App.CapschedQueuesconfView = Ember.View.extend({
+  saveMode: '',
   actions: {
-    showSaveConfigDialog: function() {
+    showSaveConfigDialog: function(opt) {
+      if (opt) {
+        this.set('saveMode', opt);
+      } else {
+        this.set('saveMode', '');
+      }
       this.$('#configNoteModalDialog').modal('show');
+    },
+    showDeleteQueueDialog: function() {
+      this.$('#deleteQueueModalDialog').modal('show');
     }
   }
 });


Mime
View raw message