Repository: ambari Updated Branches: refs/heads/branch-2.4 9a3cce9ef -> 16b223474
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/16b22347 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/16b22347 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/16b22347 Branch: refs/heads/branch-2.4 Commit: 16b2234742fdb8f0fa14603ebcc148aa37be789d Parents: 9a3cce9 Author: Pallav Kulshreshtha <[email protected]> Authored: Tue Jun 7 17:28:21 2016 +0530 Committer: Pallav Kulshreshtha <[email protected]> Committed: Tue Jun 7 17:29:59 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/16b22347/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/16b22347/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', '[email protected]', 'allQueues.length') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/16b22347/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/16b22347/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('[email protected]'), + 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','[email protected]'), + + /** * 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('[email protected]'), + + /** + * 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('[email protected]'), + + /** + * List of queues with excess of capacity + * @type {Array} + */ + overCapacityQ: function () { + return this.get('queues').filter(function (q) { + return q.get('overCapacity'); + }); + }.property('[email protected]'), + + /** + * 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/16b22347/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','[email protected]'), + 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/16b22347/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/16b22347/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">×</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/16b22347/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/16b22347/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/16b22347/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/16b22347/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'); } } });
