Repository: ambari Updated Branches: refs/heads/trunk 8ead0a50b -> 2f8de0be4
AMBARI-8659. Rolling upgrade process: implement nested views of upgrade process. (atkach via yusaku) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2f8de0be Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2f8de0be Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2f8de0be Branch: refs/heads/trunk Commit: 2f8de0be4b46221afc9b66cdc76ed18231fe3b00 Parents: 8ead0a5 Author: Yusaku Sako <yus...@hortonworks.com> Authored: Thu Dec 11 15:04:26 2014 -0800 Committer: Yusaku Sako <yus...@hortonworks.com> Committed: Thu Dec 11 15:04:26 2014 -0800 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 2 +- .../main/admin/stack_and_upgrade_controller.js | 125 +++++++++++++++- ambari-web/app/messages.js | 7 +- ambari-web/app/routes/stack_upgrade_routes.js | 4 + ambari-web/app/styles/application.less | 18 ++- .../app/templates/common/error_log_body.hbs | 4 +- .../templates/common/host_progress_popup.hbs | 4 +- .../stack_upgrade/stack_upgrade_dialog.hbs | 8 +- .../main/admin/stack_upgrade/upgrade_group.hbs | 148 +++++++++++++++++++ .../main/admin/stack_upgrade/upgrade_task.hbs | 67 --------- ambari-web/app/utils/ember_reopen.js | 6 +- ambari-web/app/utils/helper.js | 36 +++++ ambari-web/app/views.js | 2 +- .../admin/stack_upgrade/upgrade_group_view.js | 115 ++++++++++++++ .../admin/stack_upgrade/upgrade_task_view.js | 115 -------------- .../admin/stack_upgrade/upgrade_wizard_view.js | 33 ++++- .../admin/stack_and_upgrade_controller_test.js | 22 ++- .../stack_upgrade/upgrade_group_view_test.js | 40 +++++ .../stack_upgrade/upgrade_task_view_test.js | 61 -------- 19 files changed, 539 insertions(+), 278 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index 2aab326..dd816dc 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -168,7 +168,7 @@ var files = ['test/init_model_test', 'test/views/main/alerts/manage_alert_notifications_view_test', 'test/views/main/admin/stack_version/stack_version_details_test', 'test/views/main/admin/stack_upgrade/upgrade_version_box_view_test', - 'test/views/main/admin/stack_upgrade/upgrade_task_view_test', + 'test/views/main/admin/stack_upgrade/upgrade_group_view_test', 'test/views/main/dashboard/config_history_view_test', 'test/views/main/dashboard/widget_test', 'test/views/main/dashboard/widgets_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js index f8c687e..2d73ab3 100644 --- a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js +++ b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js @@ -164,11 +164,81 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage, loadUpgradeDataSuccessCallback: function (data) { App.set('upgradeState', data.Upgrade.request_status); if (data.upgrade_groups) { - this.set("upgradeData", data); + this.updateUpgradeData(data); } }, /** + * update data of Upgrade + * @param {object} newData + */ + updateUpgradeData: function (newData) { + var oldData = this.get('upgradeData'), + groupsMap = {}, + itemsMap = {}, + tasksMap = {}; + + if (Em.isNone(oldData)) { + this.initUpgradeData(newData); + } else { + //create entities maps + newData.upgrade_groups.forEach(function (newGroup) { + groupsMap[newGroup.UpgradeGroup.group_id] = newGroup.UpgradeGroup; + newGroup.upgrade_items.forEach(function (item) { + itemsMap[item.UpgradeItem.stage_id] = item.UpgradeItem; + item.tasks.forEach(function (task) { + tasksMap[task.Tasks.id] = task.Tasks; + }); + }) + }); + + //update existed entities with new data + oldData.upgradeGroups.forEach(function (oldGroup) { + oldGroup.set('status', groupsMap[oldGroup.get('group_id')].status); + oldGroup.set('progress_percent', groupsMap[oldGroup.get('group_id')].progress_percent); + oldGroup.upgradeItems.forEach(function (item) { + item.set('status', itemsMap[item.get('stage_id')].status); + item.set('progress_percent', itemsMap[item.get('stage_id')].progress_percent); + item.tasks.forEach(function (task) { + task.set('status', tasksMap[task.get('id')].status); + }); + }) + }); + } + }, + + /** + * change structure of Upgrade + * In order to maintain nested views in template object should have direct link to its properties, for example + * item.UpgradeItem.<properties> -> item.<properties> + * @param {object} newData + */ + initUpgradeData: function (newData) { + var upgradeGroups = []; + + //wrap all entities into App.upgradeEntity + newData.upgrade_groups.forEach(function (newGroup) { + var oldGroup = App.upgradeEntity.create(newGroup.UpgradeGroup); + var upgradeItems = []; + newGroup.upgrade_items.forEach(function (item) { + var oldItem = App.upgradeEntity.create(item.UpgradeItem); + var tasks = []; + item.tasks.forEach(function (task) { + tasks.pushObject(App.upgradeEntity.create(task.Tasks)); + }); + oldItem.set('tasks', tasks); + upgradeItems.pushObject(oldItem); + }); + oldGroup.set('upgradeItems', upgradeItems); + upgradeGroups.pushObject(oldGroup); + }); + this.set('upgradeData', Em.Object.create({ + upgradeGroups: upgradeGroups, + Upgrade: newData.Upgrade + })); + }, + + /** * make call to start downgrade process */ downgrade: function () { @@ -292,3 +362,56 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage, App.router.transitionTo('admin.stackUpgrade'); } }); + + +/** + * @type {Ember.Object} + * @class + */ +App.upgradeEntity = Em.Object.extend({ + + /** + * @type {boolean} + */ + errorLogOpened: false, + + /** + * @type {boolean} + */ + outputLogOpened: false, + + /** + * @type {boolean} + */ + isExpanded: false, + + /** + * @type {boolean} + */ + isRunning: function () { + return ['IN_PROGRESS'].contains(this.get('status')); + }.property('status'), + + /** + * width style of progress bar + * @type {string} + */ + progressWidth: function () { + return "width:" + Math.floor(this.get('progress')) + '%;'; + }.property('progress'), + + /** + * @type {number} + */ + progress: function () { + return Math.floor(this.get('progress_percent')); + }.property('progress_percent'), + + /** + * indicate whether entity has active link + * @type {boolean} + */ + isActive: function () { + return this.get('status') !== 'PENDING'; + }.property('status') +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 4dbeb91..0705e88 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -243,6 +243,8 @@ Em.I18n.translations = { 'common.finalize': "Finalize", 'common.severity': "Severity", 'common.dismiss': "Dismiss", + 'common.stdout': "stdout", + 'common.stderr': "stderr", 'models.alert_instance.tiggered.verbose': "Occured on {0} <br> Checked on {1}", 'models.alert_definition.triggered.verbose': "Occured on {0}", @@ -1295,10 +1297,11 @@ Em.I18n.translations = { 'admin.stackUpgrade.state.available': "Upgrade Available", 'admin.stackUpgrade.state.notAvailable': "No Upgrade Available", 'admin.stackUpgrade.state.resume': "Resume Upgrade", - 'admin.stackUpgrade.state.inProgress': "Upgrade in progress", - 'admin.stackUpgrade.state.paused': "Upgrade is paused", + 'admin.stackUpgrade.state.inProgress': "Upgrade in Progress", + 'admin.stackUpgrade.state.paused': "Upgrade Paused", 'admin.stackUpgrade.state.stopped': "Upgrade Stopped", 'admin.stackUpgrade.state.completed': "Upgrade Finished", + 'admin.stackUpgrade.state.failed': "Upgrade Failed", 'admin.stackUpgrade.state.upgrading': "Upgrading...", 'admin.stackUpgrade.hosts': "hosts", 'admin.stackUpgrade.host': "host", http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/routes/stack_upgrade_routes.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/routes/stack_upgrade_routes.js b/ambari-web/app/routes/stack_upgrade_routes.js index aca2c62..154a95b 100644 --- a/ambari-web/app/routes/stack_upgrade_routes.js +++ b/ambari-web/app/routes/stack_upgrade_routes.js @@ -27,12 +27,16 @@ module.exports = App.WizardRoute.extend({ App.router.get('updateController').set('isWorking', false); return App.ModalPopup.show({ + classNames: ['full-width-modal'], header: function () { return Em.I18n.t('admin.stackUpgrade.dialog.header').format(App.router.get('mainAdminStackAndUpgradeController').get('upgradeVersion')); }.property('App.router.mainAdminStackAndUpgradeController.upgradeVersion'), bodyClass: App.upgradeWizardView, primary: null, secondary: null, + didInsertElement: function () { + this.fitHeight(); + }, onClose: function() { var self = this; var header = Em.I18n.t('admin.stackUpgrade.state.paused'); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index aa5e8b7..1fa74fc 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -6551,8 +6551,8 @@ i.icon-asterisks { #stack-upgrade-dialog { .task-list { - overflow: auto; - .task-details { + overflow-x: hidden; + .details-box { padding: 2px 4px; margin-left: 15px; .button-row { @@ -6569,12 +6569,20 @@ i.icon-asterisks { .progress { margin-bottom: 0; } - } - .task-list>div { - padding: 5px; + padding-left: 20px; i { margin-right: 5px; } + .task-details { + .manage-controls a { + cursor: pointer; + margin-right: 12px; + } + textarea { + width: 100%; + min-height: 100px; + } + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/templates/common/error_log_body.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/error_log_body.hbs b/ambari-web/app/templates/common/error_log_body.hbs index 62f1b65..b532901 100644 --- a/ambari-web/app/templates/common/error_log_body.hbs +++ b/ambari-web/app/templates/common/error_log_body.hbs @@ -20,9 +20,9 @@ <div class="content-area"> <div class="task-detail-log-clipboard-wrap"></div> <div class="task-detail-log-maintext"> - <h5>stderr: <span class="muted">{{view.openedTask.errorLog}} </span></h5> + <h5>{{t common.stderr}}: <span class="muted">{{view.openedTask.errorLog}} </span></h5> <pre class="stderr">{{view.openedTask.stderr}}</pre> - <h5>stdout: <span class="muted"> {{view.openedTask.outputLog}} </span></h5> + <h5>{{t common.stdout}}: <span class="muted"> {{view.openedTask.outputLog}} </span></h5> <pre class="stdout">{{view.openedTask.stdout}}</pre> {{#if view.openedTask.structuredOut}} <h5>structured_out: </h5> http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/templates/common/host_progress_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/host_progress_popup.hbs b/ambari-web/app/templates/common/host_progress_popup.hbs index 01008f3..e5469ec 100644 --- a/ambari-web/app/templates/common/host_progress_popup.hbs +++ b/ambari-web/app/templates/common/host_progress_popup.hbs @@ -226,9 +226,9 @@ </div> <hr> {{/if}} - <h5>stderr: <span class="muted">{{view.openedTask.errorLog}} </span></h5> + <h5>{{t common.stderr}}: <span class="muted">{{view.openedTask.errorLog}} </span></h5> <pre class="stderr">{{view.openedTask.stderr}}</pre> - <h5>stdout: <span class="muted"> {{view.openedTask.outputLog}} </span></h5> + <h5>{{t common.stdout}}: <span class="muted"> {{view.openedTask.outputLog}} </span></h5> <pre class="stdout">{{view.openedTask.stdout}}</pre> </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_dialog.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_dialog.hbs b/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_dialog.hbs index 492e4e9..8509801 100644 --- a/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_dialog.hbs +++ b/ambari-web/app/templates/main/admin/stack_upgrade/stack_upgrade_dialog.hbs @@ -19,7 +19,7 @@ <div id="stack-upgrade-dialog"> {{#if view.isLoaded}} <div class="row-fluid"> - <div class="span2">{{t common.progress}}</div> + <div class="span2">{{statusIcon controller.upgradeData.Upgrade.request_status}} {{view.upgradeStatusLabel}}</div> <div class="span9"> <div class="progress progress-striped active"> <div class="bar" {{bindAttr style="view.progressWidth"}}></div> @@ -30,9 +30,9 @@ </div> </div> - <div class="task-list"> - {{#each group in view.groups}} - {{view App.upgradeTaskView contentBinding="group"}} + <div class="task-list limited-height-2"> + {{#each group in controller.upgradeData.upgradeGroups}} + {{view App.upgradeGroupView contentBinding="group"}} {{/each}} </div> {{else}} http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_group.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_group.hbs b/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_group.hbs new file mode 100644 index 0000000..f9dcdfc --- /dev/null +++ b/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_group.hbs @@ -0,0 +1,148 @@ +{{! +* 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-fluid"> + <div {{bindAttr class="view.content.isActive::not-active-link :span8"}}> + {{statusIcon view.content.status}} + <a href="#" {{action toggleExpanded view.content controller.upgradeData.upgradeGroups target="view"}}>{{view.content.title}}</a> + </div> + {{#if view.content.isRunning}} + <div class="span3"> + <div class="progress progress-striped active"> + <div class="bar" {{bindAttr style="view.content.progressWidth"}}></div> + </div> + </div> + <div class="span1"> + <div>{{view.content.progress}}%</div> + </div> + {{/if}} +</div> + +<div {{bindAttr class="view.content.isExpanded::hidden :task-list"}}> + + {{! List of UpgradeItem}} + {{#each item in view.content.upgradeItems}} + <div class="row-fluid"> + <div {{bindAttr class="item.isActive::not-active-link :span8"}}> + {{statusIcon item.status}} + <a href="#" {{action toggleExpanded item view.content.upgradeItems target="view"}}>{{item.context}}</a> + </div> + {{#if item.isRunning}} + <div class="span3"> + <div class="progress progress-striped active"> + <div class="bar" {{bindAttr style="item.progressWidth"}}></div> + </div> + </div> + <div class="span1"> + <div>{{item.progress}}%</div> + </div> + {{/if}} + </div> + {{#if item.isExpanded}} + + {{! List of Tasks}} + <div class="task-list"> + {{#each task in item.tasks}} + <div {{bindAttr class="task.isActive::not-active-link"}}>{{statusIcon task.status}}<a href="#" {{action toggleExpanded task item.tasks target="view"}}>{{task.command_detail}}</a></div> + {{#if task.isExpanded}} + <div class="task-details task-detail-info"> + <ul class="nav nav-tabs"> + <li class="active"><a href="#tab1" data-toggle="tab">{{t common.stdout}}</a></li> + <li><a href="#tab2" data-toggle="tab">{{t common.stderr}}</a></li> + </ul> + <div class="tab-content"> + <div class="tab-pane active" id="tab1"> + <p>{{task.host_name}}</p> + <div class="row-fluid"> + <p class="pull-left">{{task.output_log}}</p> + <div class="manage-controls pull-right"> + <a title="Click to Copy" {{action copyOutLog task target="view"}} class="task-detail-copy"> + <i class="icon-copy"></i> {{t common.copy}} + </a> + <a title="Open in New Window" {{action openLogWindow task.stdout target="view"}} class="task-detail-open-dialog"> + <i class="icon-external-link"></i> {{t common.open}} + </a> + </div> + </div> + <pre {{bindAttr class="task.outputLogOpened:hidden :stdout"}}>{{task.stdout}}</pre> + {{view Ember.TextArea valueBinding="task.stdout" classBinding="task.outputLogOpened::hidden" readonly="readonly"}} + </div> + <div class="tab-pane" id="tab2"> + <p>{{task.host_name}}</p> + <div class="row-fluid"> + <p class="pull-left">{{task.error_log}}</p> + <div class="manage-controls pull-right"> + <a title="Click to Copy" {{action copyErrLog task target="view"}} class="task-detail-copy"> + <i class="icon-copy"></i> {{t common.copy}} + </a> + <a title="Open in New Window" {{action openLogWindow task.stderr target="view"}} class="task-detail-open-dialog"> + <i class="icon-external-link"></i> {{t common.open}} + </a> + </div> + </div> + <pre {{bindAttr class="task.errorLogOpened:hidden :stderr"}}>{{task.stderr}}</pre> + {{view Ember.TextArea valueBinding="task.stderr" classBinding="task.errorLogOpened::hidden" readonly="readonly"}} + </div> + </div> + </div> + {{/if}} + {{/each}} + </div> + {{/if}} + {{/each}} +</div> + +{{#unless view.content.isExpanded}} + {{#if view.showProgressInfo}} + <div class="box details-box"> + <div> + {{t admin.stackUpgrade.dialog.inProgress}} + <a href>{{view.runningItem.context}}</a> + </div> + </div> + {{/if}} + {{#if view.isFailed}} + <div class="box details-box"> + <div> + {{t admin.stackUpgrade.dialog.failed}} + <a href>{{view.failedItem.name}}</a> + </div> + <div class="button-row"> + <button class="btn btn-danger">{{t admin.stackUpgrade.dialog.stop}}</button> + <button class="btn btn-warning">{{t admin.stackUpgrade.dialog.continue}}</button> + <button class="btn">{{t common.retry}}</button> + </div> + </div> + {{/if}} + {{#if view.isManualOpened}} + <div class="box details-box"> + <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p> + + <div class="message"> + {{view Em.Checkbox checkedBinding="view.isManualDone"}} + {{t admin.stackUpgrade.dialog.manualDone}} + </div> + <div class="button-row"> + <button class="btn btn-danger">{{t admin.stackUpgrade.dialog.stop}}</button> + <button + class="btn btn-success" {{bindAttr disabled="view.isManualProceedDisabled"}}>{{t common.proceed}}</button> + </div> + </div> + {{/if}} +{{/unless}} http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_task.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_task.hbs b/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_task.hbs deleted file mode 100644 index 511d04a..0000000 --- a/ambari-web/app/templates/main/admin/stack_upgrade/upgrade_task.hbs +++ /dev/null @@ -1,67 +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-fluid"> - <div class="span8"><i {{bindAttr class="view.iconClass"}}></i><a>{{view.content.UpgradeGroup.title}}</a></div> - - {{#if view.showProgressBar}} - <div class="span3"> - <div class="progress progress-striped active"> - <div class="bar" {{bindAttr style="view.progressWidth"}}></div> - </div> - </div> - <div class="span1"> - <div>{{view.progress}}%</div> - </div> - {{/if}} -</div> -{{#if view.isInProgress}} - <div class="box task-details"> - <div> - {{t admin.stackUpgrade.dialog.inProgress}} - <a href>{{view.runningItem.UpgradeItem.context}}</a> - </div> - </div> -{{/if}} -{{#if view.isFailed}} - <div class="box task-details"> - <div> - {{t admin.stackUpgrade.dialog.failed}} - <a href>{{view.failedItem.UpgradeItem.name}}</a> - </div> - <div class="button-row"> - <button class="btn btn-danger">{{t admin.stackUpgrade.dialog.stop}}</button> - <button class="btn btn-warning">{{t admin.stackUpgrade.dialog.continue}}</button> - <button class="btn">{{t common.retry}}</button> - </div> - </div> -{{/if}} -{{#if view.isManualOpened}} - <div class="box task-details"> - <p><strong>{{t admin.stackUpgrade.dialog.manual}}</strong></p> - <div class="message"> - {{view Em.Checkbox checkedBinding="view.isManualDone"}} - {{t admin.stackUpgrade.dialog.manualDone}} - </div> - <div class="button-row"> - <button class="btn btn-danger">{{t admin.stackUpgrade.dialog.stop}}</button> - <button class="btn btn-success" {{bindAttr disabled="view.isManualProceedDisabled"}}>{{t common.proceed}}</button> - </div> - </div> -{{/if}} http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/utils/ember_reopen.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ember_reopen.js b/ambari-web/app/utils/ember_reopen.js index 7ac69db..a879cde 100644 --- a/ambari-web/app/utils/ember_reopen.js +++ b/ambari-web/app/utils/ember_reopen.js @@ -173,4 +173,8 @@ Em.View.reopen({ console.debug('Calling set on destroyed view'); } } -}); \ No newline at end of file +}); + +Ember.TextArea.reopen({ + attributeBindings: ['readonly'] +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/utils/helper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/helper.js b/ambari-web/app/utils/helper.js index a58b732..8d7dc2a 100644 --- a/ambari-web/app/utils/helper.js +++ b/ambari-web/app/utils/helper.js @@ -723,6 +723,42 @@ App.registerBoundHelper('formatWordBreak', Em.View.extend({ })); /** + * Return <i></i> with class that correspond to status + * + * @param {string} content - status + * + * Examples: + * + * {{statusIcon view.status}} + * returns 'icon-cog' + * + */ +App.registerBoundHelper('statusIcon', Em.View.extend({ + tagName: 'i', + + /** + * relation map between status and icon class + * @type {object} + */ + statusIconMap: { + 'COMPLETED': 'icon-ok', + 'WARNING': 'icon-warning-sign', + 'FAILED': 'icon-warning-sign', + 'PENDING': 'icon-cog', + 'IN_PROGRESS': 'icon-cogs', + 'HOLDING': 'icon-pause' + }, + + classNameBindings: ['iconClass'], + /** + * @type {string} + */ + iconClass: function () { + return this.get('statusIconMap')[this.get('content')] || 'icon-question-sign'; + }.property('content') +})); + +/** * Ambari overrides the default date transformer. * This is done because of the non-standard data * sent. For example Nagios sends date as "12345678". http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index c19139a..ab4acb8 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -105,7 +105,7 @@ require('views/main/admin/serviceAccounts_view'); require('views/main/admin/stack_upgrade'); require('views/main/admin/stack_upgrade/upgrade_wizard_view'); require('views/main/admin/stack_upgrade/upgrade_version_box_view'); -require('views/main/admin/stack_upgrade/upgrade_task_view'); +require('views/main/admin/stack_upgrade/upgrade_group_view'); require('views/main/admin/stack_and_upgrade_view'); require('views/main/admin/stack_versions/menu'); require('views/main/admin/stack_versions/repo_version_view'); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/views/main/admin/stack_upgrade/upgrade_group_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_group_view.js b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_group_view.js new file mode 100644 index 0000000..23968d1 --- /dev/null +++ b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_group_view.js @@ -0,0 +1,115 @@ +/** + * 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.upgradeGroupView = Em.View.extend({ + templateName: require('templates/main/admin/stack_upgrade/upgrade_group'), + + /** + * @type {boolean} + */ + isManualDone: false, + + /** + * progress info is a box that show running UpgradeItem + * @type {boolean} + */ + showProgressInfo: function () { + return this.get('content.isRunning') && this.get('runningItem'); + }.property('content.isRunning', 'runningItem'), + + /** + * @type {boolean} + */ + isManualProceedDisabled: function () { + return !this.get('isManualDone'); + }.property('isManualDone'), + + /** + * @type {boolean} + */ + isFailed: function () { + return this.get('content.status') === 'FAILED'; + }.property('content.status'), + + /** + * if upgrade group is in progress it should have currently running item + * @type {object|undefined} + */ + runningItem: function () { + return this.get('content.upgradeItems').findProperty('status', 'IN_PROGRESS'); + }.property('content.upgradeItems.@each.status'), + + /** + * if upgrade group is failed it should have failed item + * @type {object|undefined} + */ + failedItem: function () { + return this.get('content.upgradeItems').findProperty('status', 'FAILED'); + }.property('content.upgradeItems.@each.status'), + + /** + * @type {boolean} + */ + isManualOpened: function () { + return this.get('content.status') === 'HOLDING'; + }.property('content.status'), + + /** + * Only one UpgradeGroup or UpgradeItem could be expanded at a time + * @param {object} event + */ + toggleExpanded: function (event) { + event.contexts[1].forEach(function (item) { + if (item == event.context) { + item.set('isExpanded', !event.context.get('isExpanded')); + } else { + item.set('isExpanded', false); + } + }); + }, + + /** + * + * @param {object} event + */ + copyErrLog: function(event) { + event.context.toggleProperty('errorLogOpened'); + }, + + /** + * + * @param {object} event + */ + openLogWindow: function(event) { + var newWindow = window.open(); + var newDocument = newWindow.document; + newDocument.write(event.context); + newDocument.close(); + }, + + /** + * + * @param {object} event + */ + copyOutLog: function(event) { + event.context.toggleProperty('outputLogOpened'); + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/views/main/admin/stack_upgrade/upgrade_task_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_task_view.js b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_task_view.js deleted file mode 100644 index bf57734..0000000 --- a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_task_view.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -var App = require('app'); - -App.upgradeTaskView = Em.View.extend({ - templateName: require('templates/main/admin/stack_upgrade/upgrade_task'), - - /** - * relation map between status and icon class - * @type {Object} - */ - statusIconMap: { - 'COMPLETED': 'icon-ok', - 'WARNING': 'icon-warning-sign', - 'FAILED': 'icon-warning-sign', - 'PENDING': 'icon-cog', - 'IN_PROGRESS': 'icon-cogs' - }, - - /** - * @type {Boolean} - */ - isManualDone: false, - - /** - * @type {Boolean} - */ - isManualProceedDisabled: function () { - return !this.get('isManualDone'); - }.property('isManualDone'), - - /** - * @type {string} - */ - iconClass: function () { - return this.get('statusIconMap')[this.get('content.UpgradeGroup.status')] || 'icon-question-sign'; - }.property('content.UpgradeGroup.status'), - - /** - * @type {Boolean} - */ - isFailed: function () { - return this.get('content.UpgradeGroup.status') === 'FAILED'; - }.property('content.UpgradeGroup.status'), - - /** - * @type {Boolean} - */ - showProgressBar: function () { - return ['IN_PROGRESS', 'FAILED'].contains(this.get('content.UpgradeGroup.status')) && this.get('content.UpgradeGroup.type') !== 'manual'; - }.property('content.UpgradeGroup.status'), - - /** - * @type {Boolean} - */ - isInProgress: function () { - return this.get('content.UpgradeGroup.status') === 'IN_PROGRESS' && this.get('content.UpgradeGroup.type') !== 'manual'; - }.property('content.UpgradeGroup.status'), - - /** - * width style of progress bar - * @type {String} - */ - progressWidth: function () { - return "width:" + Math.floor(this.get('progress')) + '%;'; - }.property('content.UpgradeGroup.progress_percent'), - - /** - * @type {number} - */ - progress: function () { - return Math.floor(this.get('content.UpgradeGroup.progress_percent')) - }.property('content.UpgradeGroup.progress_percent'), - - /** - * if upgrade group is in progress it should have currently running item - * @type {Object|null} - */ - runningItem: function () { - return this.get('content.upgrade_items').findProperty('UpgradeItem.status', 'IN_PROGRESS'); - }.property('content.upgrade_items.@each.UpgradeItem.status'), - - /** - * if upgrade group is failed it should have failed item - * @type {Object|null} - */ - failedItem: function () { - return this.get('content.upgrade_items').findProperty('UpgradeItem.status', 'FAILED'); - }.property('content.upgrade_items.@each.UpgradeItem.status'), - - /** - * @type {Boolean} - */ - isManualOpened: function () { - //TODO modify logic according to actual API - return this.get('content.UpgradeGroup.status') === 'IN_PROGRESS' && this.get('content.UpgradeGroup.type') === 'manual' - }.property('content.UpgradeGroup.status', 'content.UpgradeGroup.type') -}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js index b3eaab7..d617437 100644 --- a/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js +++ b/ambari-web/app/views/main/admin/stack_upgrade/upgrade_wizard_view.js @@ -52,6 +52,30 @@ App.upgradeWizardView = Em.View.extend({ }.property('controller.upgradeData.Upgrade.progress_percent'), /** + * label of Upgrade status + * @type {string} + */ + upgradeStatusLabel: function() { + switch (this.get('controller.upgradeData.Upgrade.request_status')) { + case 'PENDING': + case 'IN_PROGRESS': + return Em.I18n.t('admin.stackUpgrade.state.inProgress'); + break; + case 'COMPLETED': + return Em.I18n.t('admin.stackUpgrade.state.completed'); + break; + case 'HOLDING': + return Em.I18n.t('admin.stackUpgrade.state.paused'); + break; + case 'FAILED': + return Em.I18n.t('admin.stackUpgrade.state.paused'); + break; + default: + return "" + } + }.property('controller.upgradeData.Upgrade.request_status'), + + /** * start polling upgrade data */ startPolling: function () { @@ -88,12 +112,5 @@ App.upgradeWizardView = Em.View.extend({ self.get('controller').loadUpgradeData(); self.doPolling(); }, App.bgOperationsUpdateInterval)); - }, - - /** - * @type {Array} - */ - groups: function () { - return this.get('controller.upgradeData.upgrade_groups'); - }.property('controller.upgradeData.upgrade_groups') + } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js b/ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js index 104dfca..f20d9a4 100644 --- a/ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js +++ b/ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js @@ -186,22 +186,28 @@ describe('App.MainAdminStackAndUpgradeController', function() { }); describe("#loadUpgradeDataSuccessCallback()", function() { + beforeEach(function () { + sinon.stub(controller, 'updateUpgradeData', Em.K); + }); + afterEach(function () { + controller.updateUpgradeData.restore(); + }); it("", function() { var data = { "Upgrade": { "request_status": "COMPLETED" }, "upgrade_groups": [ - { - "UpgradeGroup": { - "id": 1 - }, - "upgrade_items": [] - } - ]}; + { + "UpgradeGroup": { + "id": 1 + }, + "upgrade_items": [] + } + ]}; controller.loadUpgradeDataSuccessCallback(data); - expect(controller.get('upgradeData')).to.eql(data); expect(App.get('upgradeState')).to.equal('COMPLETED'); + expect(controller.updateUpgradeData.called).to.be.true; }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/test/views/main/admin/stack_upgrade/upgrade_group_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_group_view_test.js b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_group_view_test.js new file mode 100644 index 0000000..f9002e8 --- /dev/null +++ b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_group_view_test.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'); +require('views/main/admin/stack_upgrade/upgrade_group_view'); + +describe('App.upgradeGroupView', function () { + var view = App.upgradeGroupView.create({ + content: Em.Object.create({}) + }); + + describe("#isFailed", function () { + it("task is not failed", function () { + view.set('content.status', 'COMPLETED'); + view.propertyDidChange('isFailed'); + expect(view.get('isFailed')).to.be.false; + }); + it("task is not failed", function () { + view.set('content.status', 'FAILED'); + view.propertyDidChange('isFailed'); + expect(view.get('isFailed')).to.be.true; + }); + }); +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/2f8de0be/ambari-web/test/views/main/admin/stack_upgrade/upgrade_task_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_task_view_test.js b/ambari-web/test/views/main/admin/stack_upgrade/upgrade_task_view_test.js deleted file mode 100644 index b40ea28..0000000 --- a/ambari-web/test/views/main/admin/stack_upgrade/upgrade_task_view_test.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -var App = require('app'); -require('views/main/admin/stack_upgrade/upgrade_task_view'); - -describe('App.upgradeTaskView', function () { - var view = App.upgradeTaskView.create({ - content: Em.Object.create({ - UpgradeGroup: {} - }) - }); - - describe("#iconClass", function () { - it("status has icon", function () { - view.set('statusIconMap', { - 'S1': 'icon1' - }); - view.set('content.UpgradeGroup.status', 'S1'); - view.propertyDidChange('iconClass'); - expect(view.get('iconClass')).to.equal('icon1'); - }); - it("status undefined", function () { - view.set('statusIconMap', { - 'S1': 'icon1' - }); - view.set('content.UpgradeGroup.status', 'S2'); - view.propertyDidChange('iconClass'); - expect(view.get('iconClass')).to.equal('icon-question-sign'); - }); - }); - - describe("#isFailed", function () { - it("task is not failed", function () { - view.set('content.UpgradeGroup.status', 'COMPLETED'); - view.propertyDidChange('isFailed'); - expect(view.get('isFailed')).to.be.false; - }); - it("task is not failed", function () { - view.set('content.UpgradeGroup.status', 'FAILED'); - view.propertyDidChange('isFailed'); - expect(view.get('isFailed')).to.be.true; - }); - }); -});