You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/09/14 14:32:16 UTC
ambari git commit: AMBARI-21933 - UI: Implement breadcrumbs in
Background Operations modal (Jason Golieb via jonathanhurley)
Repository: ambari
Updated Branches:
refs/heads/trunk 03edb8e78 -> 38604db2f
AMBARI-21933 - UI: Implement breadcrumbs in Background Operations modal (Jason Golieb via jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/38604db2
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/38604db2
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/38604db2
Branch: refs/heads/trunk
Commit: 38604db2f17eb7eac3b4fe5bf308842d5018ee00
Parents: 03edb8e
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Sep 14 10:23:32 2017 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Thu Sep 14 10:23:32 2017 -0400
----------------------------------------------------------------------
.../global/background_operations_controller.js | 9 +-
.../progress_popup_controller.js | 8 +-
ambari-web/app/messages.js | 2 +
ambari-web/app/styles/modal_popups.less | 11 +
ambari-web/app/templates/common/breadcrumbs.hbs | 6 +-
.../templates/common/host_progress_popup.hbs | 27 +-
ambari-web/app/utils/host_progress_popup.js | 121 +++-
ambari-web/app/views/common/breadcrumbs_view.js | 24 +-
.../common/host_progress_popup_body_view.js | 316 ++++++---
.../global/background_operations_test.js | 4 +-
.../progress_popup_controller_test.js | 4 +
.../test/utils/host_progress_popup_test.js | 7 +-
.../test/views/common/breadcrumbs_view_test.js | 30 +-
.../host_progress_popup_body_view_test.js | 641 ++++++++++++-------
14 files changed, 805 insertions(+), 405 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/controllers/global/background_operations_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/background_operations_controller.js b/ambari-web/app/controllers/global/background_operations_controller.js
index de420b5..7cf4d72 100644
--- a/ambari-web/app/controllers/global/background_operations_controller.js
+++ b/ambari-web/app/controllers/global/background_operations_controller.js
@@ -40,13 +40,13 @@ App.BackgroundOperationsController = Em.Controller.extend({
operationsCount: 10,
/**
* Possible levels:
- * REQUESTS_LIST
+ * OPS_LIST
* HOSTS_LIST
* TASKS_LIST
* TASK_DETAILS
*/
levelInfo: Em.Object.create({
- name: 'REQUESTS_LIST',
+ name: "OPS_LIST",
requestId: null,
taskId: null
}),
@@ -258,7 +258,7 @@ App.BackgroundOperationsController = Em.Controller.extend({
}
this.removeOldRequests(currentRequestIds);
this.set("allOperationsCount", runningServices);
- this.set('isShowMoreAvailable', countGot >= countIssued);
+ this.set('isShowMoreAvailable', countGot > countIssued);
this.set('serviceTimestamp', App.dateTimeWithTimeZone());
},
@@ -368,6 +368,9 @@ App.BackgroundOperationsController = Em.Controller.extend({
var self = this;
App.router.get('userSettingsController').dataLoading('show_bg').done(function (initValue) {
App.updater.immediateRun('requestMostRecent');
+
+ App.HostPopup.set("breadcrumbs", [ App.HostPopup.get("rootBreadcrumb") ]);
+
if (self.get('popupView') && App.HostPopup.get('isBackgroundOperations')) {
self.set('popupView.isNotShowBgChecked', !initValue);
self.set('popupView.isOpen', true);
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/controllers/main/admin/highAvailability/progress_popup_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/highAvailability/progress_popup_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/progress_popup_controller.js
index 4cbe59b..6e0ee5e 100644
--- a/ambari-web/app/controllers/main/admin/highAvailability/progress_popup_controller.js
+++ b/ambari-web/app/controllers/main/admin/highAvailability/progress_popup_controller.js
@@ -130,7 +130,7 @@ App.HighAvailabilityProgressPopupController = Ember.Controller.extend({
})
}, this);
},
-
+
doPolling: function () {
var self = this;
this.set('progressController.logs', []);
@@ -158,7 +158,7 @@ App.HighAvailabilityProgressPopupController = Ember.Controller.extend({
if (this.get('requestIds.length') === this.get('hostsData.length')) {
var popupTitle = this.get('popupTitle');
this.calculateHostsData(hostsData);
- App.HostPopup.initPopup(popupTitle, this);
+ App.HostPopup.initPopup(popupTitle, this, false, this.get("requestIds")[0]);
if (this.isRequestRunning(hostsData)) {
if (this.get('progressController.name') === 'mainAdminStackAndUpgradeController') {
this.doPolling();
@@ -180,6 +180,7 @@ App.HighAvailabilityProgressPopupController = Ember.Controller.extend({
var hosts = [];
var hostsMap = {};
var popupTitle = this.get('popupTitle');
+ var id = data[0].Requests.id;
data.forEach(function (request) {
request.tasks.forEach(function (task) {
@@ -199,7 +200,7 @@ App.HighAvailabilityProgressPopupController = Ember.Controller.extend({
hosts.push(hostsMap[host]);
}
this.set('services', [
- {name: popupTitle, hosts: hosts}
+ {id: id, name: popupTitle, hosts: hosts}
]);
this.set('serviceTimestamp', App.dateTime());
if (!this.isRequestRunning(data)) {
@@ -293,4 +294,3 @@ App.HighAvailabilityProgressPopupController = Ember.Controller.extend({
}
});
-
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 869608a..568e537 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -127,6 +127,7 @@ Em.I18n.translations = {
'common.generate.blueprint':'Generate Blueprint',
'common.message':'Message',
'common.tasks':'Tasks',
+ 'common.taskLog':'Task Log',
'common.open':'Open',
'common.copy':'Copy',
'common.complete':'Complete',
@@ -216,6 +217,7 @@ Em.I18n.translations = {
'common.notAvailable': 'Not Available',
'common.na': 'n/a',
'common.operations': 'Operations',
+ 'common.backgroundOperations': 'Background Operations',
'common.startTime': 'Start Time',
'common.duration': 'Duration',
'common.reinstall': 'Re-Install',
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/styles/modal_popups.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/modal_popups.less b/ambari-web/app/styles/modal_popups.less
index f7fe88b..97083d2 100644
--- a/ambari-web/app/styles/modal_popups.less
+++ b/ambari-web/app/styles/modal_popups.less
@@ -21,6 +21,17 @@
outline: none;
}
+#modal-label {
+ margin-left: 20px;
+ margin-right: 20px;
+ text-indent: -20px;
+ line-height: 1.3em;
+
+ a:not(.disabled) {
+ cursor: pointer;
+ }
+}
+
.host-component-popup-wrap {
.task-top-wrap {
.operation-name-top {
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/templates/common/breadcrumbs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/breadcrumbs.hbs b/ambari-web/app/templates/common/breadcrumbs.hbs
index 89353d9..363b306 100644
--- a/ambari-web/app/templates/common/breadcrumbs.hbs
+++ b/ambari-web/app/templates/common/breadcrumbs.hbs
@@ -17,8 +17,12 @@
}}
{{#each item in view.items}}
+ {{#if item.itemView}}
+ {{view item.itemView}}
+ {{else}}
<a {{bindAttr class="item.disabled:disabled"}} {{action moveTo item target="view"}}>
{{{item.formattedLabel}}}
</a>
+ {{/if}}
{{#unless item.isLast}} / {{/unless}}
-{{/each}}
\ No newline at end of file
+{{/each}}
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/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 03c014c..f5b1c73 100644
--- a/ambari-web/app/templates/common/host_progress_popup.hbs
+++ b/ambari-web/app/templates/common/host_progress_popup.hbs
@@ -19,11 +19,12 @@
<div class="host-component-popup-wrap col-sm-12">
{{#if view.parentView.isLoaded}}
-{{!-- SERVICES --}}
+{{!-- OPERATIONS --}}
<div {{bindAttr class="view.parentView.isServiceListHidden:hidden :task-list-main-wrap :table-body-wrap"}}>
<div class="row top-wrap">
- <div class="table-controls row col-sm-12 pull-right">
+ <h2 class="table-title col-sm-6">{{view view.parentView.titleClass}}</h2>
+ <div class="table-controls row col-sm-6 pull-right">
<div class="col-sm-12">
<div class="btn-group pull-right">
{{view Ember.Select
@@ -53,7 +54,7 @@
<table class="table table-hover">
<tbody>
{{#each servicesInfo in view.services}}
- <tr {{action gotoHosts servicesInfo}} {{bindAttr class="servicesInfo.isVisible::hidden :pointer"}}>
+ <tr {{action onOpClick servicesInfo}} {{bindAttr class="servicesInfo.isVisible::hidden :pointer"}}>
<td class="col-sm-3">
{{view statusIcon servicesInfoBinding="servicesInfo"}}
<a href="#">
@@ -116,11 +117,6 @@
classNames="form-control"
}}
</div>
- {{#if controller.isBackgroundOperations}}
- <button type="button" class="btn btn-link pull-right" {{action backToServiceList}}>
- <i class="glyphicon glyphicon-arrow-left"></i> {{t common.operations}}
- </button>
- {{/if}}
</div>
</div>
</div>
@@ -148,7 +144,7 @@
<table class="table table-hover">
<tbody>
{{#each hostInfo in view.pageContent}}
- <tr {{action gotoTasks hostInfo}} {{bindAttr class="hostInfo.isVisible::hidden :pointer"}}>
+ <tr {{action onHostClick hostInfo}} {{bindAttr class="hostInfo.isVisible::hidden :pointer"}}>
<td class="col-sm-6 text-nowrap">
{{view statusIcon servicesInfoBinding="hostInfo"}}
<a href="#">
@@ -206,9 +202,6 @@
classNames="form-control"
}}
</div>
- <button type="button" class="btn btn-link pull-right" {{action backToHostList}}>
- <i class="glyphicon glyphicon-arrow-left"></i> {{t common.hosts}}
- </button>
</div>
</div>
</div>
@@ -220,7 +213,7 @@
<table class="table table-hover">
<tbody>
{{#each taskInfo in view.tasks}}
- <tr {{action toggleTaskLog taskInfo}} {{bindAttr class="taskInfo.isVisible::hidden :pointer"}}>
+ <tr {{action onTaskClick taskInfo}} {{bindAttr class="taskInfo.isVisible::hidden :pointer"}}>
<td class="col-sm-3">
{{view statusIcon servicesInfoBinding="taskInfo"}}
<a href="#">
@@ -258,10 +251,7 @@
<div {{bindAttr class="view.parentView.isLogWrapHidden:hidden :task-detail-info view.hostComponentLogsExists:task-detail-info-tabbed"}}>
<div class="task-top-wrap top-wrap">
<div {{bindAttr class="view.hostComponentLogsExists:task-detail-log-nav-actions :row"}}>
- <h2 class="table-title col-sm-5">
- <i {{bindAttr class="view.openedTask.status :task-detail-status-ico view.openedTask.icon"}}></i>
- {{view.openedTask.commandDetail}}
- </h2>
+ <h2 class="table-title col-sm-5">{{t common.taskLog}}</h2>
<div class="table-controls row col-sm-7 pull-right">
<div class="col-sm-12">
{{#if App.supports.logSearch}}
@@ -279,9 +269,6 @@
<button type="button" class="btn btn-link pull-right copy-clipboard" {{translateAttr title="common.fullLogPopup.clickToCopy"}} {{action "textTrigger" taskInfo target="view"}}>
<i class="glyphicon glyphicon-copy"></i> {{t common.copy}}
</button>
- <button type="button" class="btn btn-link pull-right" {{action backToTaskList}}>
- <i class="glyphicon glyphicon-arrow-left"></i> {{t common.tasks}}
- </button>
</div>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/utils/host_progress_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/host_progress_popup.js b/ambari-web/app/utils/host_progress_popup.js
index 5bd02cd..edba87b 100644
--- a/ambari-web/app/utils/host_progress_popup.js
+++ b/ambari-web/app/utils/host_progress_popup.js
@@ -120,6 +120,14 @@ App.HostPopup = Em.Object.create({
*/
popupHeaderName: '',
+ //This is what the breadcrumbs will be reset to every time the modal is opened.
+ rootBreadcrumb: null,
+
+ /**
+ * @type {object[]}
+ */
+ breadcrumbs: [],
+
operationInfo: null,
/**
@@ -293,17 +301,21 @@ App.HostPopup = Em.Object.create({
*/
initPopup: function (serviceName, controller, isBackgroundOperations, requestId) {
if (App.get('isClusterUser')) return;
+
if (!isBackgroundOperations) {
this.clearHostPopup();
- this.set("popupHeaderName", serviceName);
+ this.set("rootBreadcrumb", { label: serviceName });
+ } else {
+ this.set("rootBreadcrumb", { label: Em.I18n.t("common.backgroundOperations") });
}
this.setProperties({
+ breadcrumbs: [ this.get("rootBreadcrumb") ],
currentServiceId: requestId,
serviceName: serviceName,
dataSourceController: controller,
isBackgroundOperations: isBackgroundOperations,
- inputData: this.get("dataSourceController.services")
+ inputData: controller.get("services")
});
if (isBackgroundOperations) {
@@ -311,6 +323,7 @@ App.HostPopup = Em.Object.create({
} else {
this.onHostUpdate();
}
+
return this.createPopup();
},
@@ -438,10 +451,12 @@ App.HostPopup = Em.Object.create({
* @method onServiceUpdate
*/
onServiceUpdate: function (isServiceListHidden) {
- if (this.get('isBackgroundOperations') && this.get("inputData")) {
- var servicesInfo = this.get("servicesInfo");
- var currentServices = [];
- this.get("inputData").forEach(function (service, index) {
+ var servicesInfo = this.get("servicesInfo");
+ var currentServices = [];
+
+ var inputData = this.get("inputData");
+ if (inputData) {
+ inputData.forEach(function (service, index) {
var updatedService;
var id = service.id;
currentServices.push(id);
@@ -456,9 +471,10 @@ App.HostPopup = Em.Object.create({
}
updatedService.set('isAbortable', App.isAuthorized('SERVICE.START_STOP') && this.isAbortableByStatus(service.status));
}, this);
- this.removeOldServices(servicesInfo, currentServices);
- this.setBackgroundOperationHeader(isServiceListHidden);
}
+
+ this.removeOldServices(servicesInfo, currentServices);
+ this.setBackgroundOperationHeader(isServiceListHidden);
},
/**
@@ -513,8 +529,8 @@ App.HostPopup = Em.Object.create({
barColor: status[2],
isInProgress: status[3],
barWidth: "width:" + newData.progress + "%;",
- sourceRequestScheduleId: newData.get('sourceRequestScheduleId'),
- contextCommand: newData.get('contextCommand')
+ sourceRequestScheduleId: newData.get && newData.get('sourceRequestScheduleId'),
+ contextCommand: newData.get && newData.get('contextCommand')
});
},
@@ -586,8 +602,7 @@ App.HostPopup = Em.Object.create({
if (existedHosts && existedHosts.length && this.get('currentServiceId') === this.get('previousServiceId')) {
this._processingExistingHostsWithSameService(hostsMap);
- }
- else {
+ } else {
var hostsArr = this._hostMapProcessing(hostsMap);
hostsArr = hostsArr.sortProperty('name');
hostsArr.setEach("serviceName", this.get("serviceName"));
@@ -595,7 +610,7 @@ App.HostPopup = Em.Object.create({
self.set('previousServiceId', this.get('currentServiceId'));
}
}
- var operation = this.get('servicesInfo').findProperty('name', this.get('serviceName'));
+ var operation = this.get('servicesInfo').findProperty('id', this.get('currentServiceId'));
this.set('operationInfo', !operation || operation && operation.get('progress') === 100 ? null : operation);
},
@@ -610,11 +625,11 @@ App.HostPopup = Em.Object.create({
var hostsData;
var hostsMap = {};
var inputData = this.get('inputData');
+
if (this.get('isBackgroundOperations') && this.get("currentServiceId")) {
//hosts popup for Background Operations
hostsData = inputData.findProperty("id", this.get("currentServiceId"));
- }
- else {
+ } else {
if (this.get("serviceName")) {
//hosts popup for Wizards
hostsData = inputData.findProperty("name", this.get("serviceName"));
@@ -625,14 +640,14 @@ App.HostPopup = Em.Object.create({
if (hostsData.hostsMap) {
//hosts data come from Background Operations as object map
hostsMap = hostsData.hostsMap;
- }
- else {
+ } else {
if (hostsData.hosts) {
//hosts data come from Wizard as array
hostsMap = hostsData.hosts.toMapByProperty('name');
}
}
}
+
return hostsMap;
},
@@ -695,8 +710,10 @@ App.HostPopup = Em.Object.create({
var existedHosts = self.get('hosts');
var detailedProperties = this.get('detailedProperties');
var detailedPropertiesKeys = Em.keys(detailedProperties);
+
existedHosts.forEach(function (host) {
var newHostInfo = hostsMap[host.get('name')];
+
//update only hosts with changed tasks or currently opened tasks of host
if (newHostInfo &&
(!this.get('isBackgroundOperations') ||
@@ -704,6 +721,7 @@ App.HostPopup = Em.Object.create({
this.get('currentHostName') === host.get('name'))) {
var hostStatus = self.getStatus(newHostInfo.logTasks);
var hostProgress = self.getProgress(newHostInfo.logTasks);
+
host.setProperties({
status: App.format.taskStatus(hostStatus[0]),
icon: hostStatus[1],
@@ -713,27 +731,33 @@ App.HostPopup = Em.Object.create({
barWidth: "width:" + hostProgress + "%;",
logTasks: newHostInfo.logTasks
});
+
var existTasks = host.get('tasks');
+
if (existTasks) {
newHostInfo.logTasks.forEach(function (_task) {
var existTask = existTasks.findProperty('id', _task.Tasks.id);
+
if (existTask) {
var status = _task.Tasks.status;
+
detailedPropertiesKeys.forEach(function (key) {
var name = detailedProperties[key];
var value = _task.Tasks[name];
+
if (!Em.isNone(value)) {
existTask.set(key, value);
}
}, this);
+
existTask.setProperties({
status: App.format.taskStatus(status),
startTime: date.startTime(_task.Tasks.start_time),
duration: date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time)
});
+
existTask = self._handleRebalanceHDFS(_task, existTask);
- }
- else {
+ } else {
existTasks.pushObject(this.createTask(_task));
}
}, this);
@@ -785,26 +809,63 @@ App.HostPopup = Em.Object.create({
this.set('isPopup', App.ModalPopup.show({
/**
+ * Controls visiblity of Task Details view.
* @type {boolean}
*/
isLogWrapHidden: true,
/**
+ * Controls visiblity of Tasks view.
* @type {boolean}
*/
isTaskListHidden: true,
/**
+ * Controls visiblity of Hosts view.
* @type {boolean}
*/
isHostListHidden: true,
/**
+ * Controls visiblity of Background Operations view.
* @type {boolean}
*/
isServiceListHidden: false,
/**
+ * Single function to handle changing the currently displayed view in the modal.
+ * Use this rather than setting the booleans above directly.
+ */
+ switchView: function(to) {
+ switch (to) {
+ case "OPS_LIST":
+ this.set("isLogWrapHidden", true);
+ this.set("isTaskListHidden", true);
+ this.set("isHostListHidden", true);
+ this.set("isServiceListHidden", false);
+ break;
+ case "HOSTS_LIST":
+ this.set("isLogWrapHidden", true);
+ this.set("isTaskListHidden", true);
+ this.set("isHostListHidden", false);
+ this.set("isServiceListHidden", true);
+ break;
+ case "TASKS_LIST":
+ this.set("isLogWrapHidden", true);
+ this.set("isTaskListHidden", false);
+ this.set("isHostListHidden", true);
+ this.set("isServiceListHidden", true);
+ break;
+ case "TASK_DETAILS":
+ this.set("isLogWrapHidden", false);
+ this.set("isTaskListHidden", true);
+ this.set("isHostListHidden", true);
+ this.set("isServiceListHidden", true);
+ break;
+ }
+ },
+
+ /**
* @type {boolean}
*/
isHideBodyScroll: true,
@@ -838,7 +899,25 @@ App.HostPopup = Em.Object.create({
/**
* @type {Em.View}
*/
- headerClass: Em.View.extend({
+ headerClass: App.BreadcrumbsView.extend({
+ controller: this,
+ items: function () {
+ let items = this.get('controller.breadcrumbs');
+ items = items.map(item => App.BreadcrumbItem.extend(item).create());
+ if (items.length) {
+ items.get('lastObject').setProperties({
+ disabled: true,
+ isLast: true
+ });
+ }
+ return items;
+ }.property('controller.breadcrumbs')
+ }),
+
+ /**
+ * @type {Em.View}
+ */
+ titleClass: Em.View.extend({
controller: this,
template: Em.Handlebars.compile('{{popupHeaderName}} ' +
'{{#unless view.parentView.isHostListHidden}}{{#if controller.operationInfo.isAbortable}}' +
@@ -888,7 +967,7 @@ App.HostPopup = Em.Object.create({
this.set('isOpen', false);
if (isBackgroundOperations) {
$(this.get('element')).detach();
- App.router.get('backgroundOperationsController').set('levelInfo.name', 'REQUESTS_LIST');
+ App.router.get('backgroundOperationsController').set('levelInfo.name', 'OPS_LIST');
} else {
this.hide();
self.set('isPopup', null);
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/views/common/breadcrumbs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/breadcrumbs_view.js b/ambari-web/app/views/common/breadcrumbs_view.js
index e35a196..7c5ec4e 100644
--- a/ambari-web/app/views/common/breadcrumbs_view.js
+++ b/ambari-web/app/views/common/breadcrumbs_view.js
@@ -60,6 +60,14 @@ App.BreadcrumbItem = Em.Object.extend({
labelBindingPath: '',
/**
+ * View shown as breadcrumb.
+ * If provied, <code>itemView</code> supersedes <code>label</code> and <code>labelBindingPath</code>.
+ *
+ * @type {object}
+ */
+ itemView: null,
+
+ /**
* Determines if breadcrumb is disabled
*
* @type {boolean}
@@ -74,7 +82,16 @@ App.BreadcrumbItem = Em.Object.extend({
isLast: false,
/**
+ * Invoke this action when click on breadcrumb item
+ * If provided, <code>action</code> supersedes <code>route</code>.
+ *
+ * @type {Function}
+ */
+ action: null,
+
+ /**
* Move user to this route when click on breadcrumb item (don't add prefix <code>main</code>)
+ * This is used if an action is not defined.
*
* @type {string}
*/
@@ -116,7 +133,12 @@ App.BreadcrumbItem = Em.Object.extend({
},
transition: function () {
- return App.router.route('main/' + this.get('route'));
+ const action = this.get('action');
+ if (action) {
+ return action();
+ } else {
+ return App.router.route('main/' + this.get('route'));
+ }
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/app/views/common/host_progress_popup_body_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/host_progress_popup_body_view.js b/ambari-web/app/views/common/host_progress_popup_body_view.js
index 057f8bc..49d7dea 100644
--- a/ambari-web/app/views/common/host_progress_popup_body_view.js
+++ b/ambari-web/app/views/common/host_progress_popup_body_view.js
@@ -219,6 +219,13 @@ App.HostProgressPopupBodyView = App.TableView.extend({
taskCategory: null,
/**
+ * Indicates current level displayed.
+ *
+ * @type {string}
+ */
+ currentLevel: "",
+
+ /**
* flag to indicate whether level data has already been loaded
* applied only to HOSTS_LIST and TASK_DETAILS levels, whereas async query used to obtain data
*
@@ -309,8 +316,11 @@ App.HostProgressPopupBodyView = App.TableView.extend({
* @method resizeHandler
*/
resizeHandler: function() {
- if (this.get('state') === 'destroyed' || !this.get('parentView.isOpen')) return;
- var modal = this.get('parentView').$().find('.modal'),
+ const parentView = this.get('parentView');
+
+ if (!parentView || !parentView.$ || !parentView.$() || this.get('state') === 'destroyed' || !parentView.get('isOpen')) return;
+
+ var modal = parentView.$().find('.modal'),
headerHeight = $(modal).find('.modal-header').outerHeight(true),
modalFooterHeight = $(modal).find('.modal-footer').outerHeight(true),
taskTopWrapHeight = $(modal).find('.top-wrap:visible').outerHeight(true),
@@ -318,9 +328,9 @@ App.HostProgressPopupBodyView = App.TableView.extend({
contentPaddingBottom = parseFloat($(modal).find('.modal-dialog').css('marginBottom')) || 0,
hostsPageBarHeight = $(modal).find('#host-info tfoot').outerHeight(true),
logComponentFileNameHeight = $(modal).find('#host-info tfoot').outerHeight(true),
- levelName = this.get('currentLevelName'),
+ levelName = this.get('currentLevel'),
boLevelHeightMap = {
- 'REQUESTS_LIST': {
+ 'OPS_LIST': {
height: window.innerHeight - 2*modalTopOffset - headerHeight - taskTopWrapHeight - modalFooterHeight - contentPaddingBottom,
target: '#service-info'
},
@@ -355,8 +365,6 @@ App.HostProgressPopupBodyView = App.TableView.extend({
}
},
- currentLevelName: Em.computed.alias('controller.dataSourceController.levelInfo.name'),
-
/**
* Preset values on init
*
@@ -364,13 +372,12 @@ App.HostProgressPopupBodyView = App.TableView.extend({
*/
setOnStart: function () {
this.set('serviceCategory', this.get('categories').findProperty('value', 'all'));
+
if (this.get("controller.isBackgroundOperations")) {
this.get('controller').setSelectCount(this.get("services"), this.get('categories'));
this.updateHostInfo();
- }
- else {
- this.set("parentView.isHostListHidden", false);
- this.set("parentView.isServiceListHidden", true);
+ } else {
+ this.get('parentView').switchView("HOSTS_LIST");
}
},
@@ -381,12 +388,7 @@ App.HostProgressPopupBodyView = App.TableView.extend({
*/
resetState: function () {
if (this.get('parentView.isOpen')) {
- this.get('parentView').setProperties({
- isLogWrapHidden: true,
- isTaskListHidden: true,
- isHostListHidden: true,
- isServiceListHidden: false
- });
+ this.get('parentView').switchView("OPS_LIST");
this.get("controller").setBackgroundOperationHeader(false);
this.get('controller.hosts').clear();
this.setOnStart();
@@ -526,69 +528,148 @@ App.HostProgressPopupBodyView = App.TableView.extend({
this.set('isPaginate', !!isPaginate);
}.observes('tasks.@each.status', 'hosts.@each.status', 'parentView.isTaskListHidden', 'parentView.isHostListHidden', 'services.@each.status'),
+ setBreadcrumbs: function (level) {
+ const breadcrumbs = [];
+ const self = this;
+ const opsCrumb = this.get("controller.rootBreadcrumb");
+
+ if (opsCrumb) {
+ opsCrumb.action = function () { self.switchLevel("OPS_LIST"); }
+
+ const opCrumb = {
+ label: this.get("controller.serviceName"),
+ action: function () { self.switchLevel("HOSTS_LIST", self.get('controller.servicesInfo').findProperty('id', self.get('controller.currentServiceId'))); }
+ }
+
+ const hostCrumb = {
+ label: this.get("controller.currentHostName"),
+ action: function () { self.switchLevel("TASKS_LIST", self.get('currentHost')); }
+ }
+
+ const taskCrumb = {
+ itemView: Em.View.extend({
+ tagName: "span",
+ controller: self,
+ template: Em.Handlebars.compile('<i style="margin-left: 20px;" {{bindAttr class="openedTask.status :task-detail-status-ico openedTask.icon"}}></i>{{openedTask.commandDetail}}')
+ })
+ }
+
+ switch (level) {
+ case "OPS_LIST":
+ breadcrumbs.push(opsCrumb);
+ break;
+ case "HOSTS_LIST":
+ breadcrumbs.push(opsCrumb);
+ if (opCrumb.label === breadcrumbs[0].label) {
+ breadcrumbs.pop();
+ }
+ breadcrumbs.push(opCrumb);
+ break;
+ case "TASKS_LIST":
+ breadcrumbs.push(opsCrumb);
+ if (opCrumb.label === breadcrumbs[0].label) {
+ breadcrumbs.pop();
+ }
+ breadcrumbs.push(opCrumb);
+ breadcrumbs.push(hostCrumb);
+ break;
+ case "TASK_DETAILS":
+ breadcrumbs.push(opsCrumb);
+ if (opCrumb.label === breadcrumbs[0].label) {
+ breadcrumbs.pop();
+ }
+ breadcrumbs.push(opCrumb);
+ breadcrumbs.push(hostCrumb);
+ breadcrumbs.push(taskCrumb);
+ break;
+ }
+
+ this.set('controller.breadcrumbs', breadcrumbs);
+ }
+ },
+
/**
- * control data uploading, depending on which display level is showed
+ * Sets up and tears down the different views in the modal when switching.
+ * Calls switchView() on the controller to perform the actual view switch.
*
* @param {string} levelName
* @method switchLevel
*/
- switchLevel: function (levelName, isBackToLevel = false) {
- var dataSourceController = this.get('controller.dataSourceController');
- var args = [].slice.call(arguments);
- this.get('hostComponentLogs').clear();
+ switchLevel: function (levelName, context) {
+ const prevLevel = this.get('controller.dataSourceController.levelInfo.name');
+
+ //leaving level - do any cleanup here
+ switch (prevLevel) {
+ case "OPS_LIST":
+ break;
+ case "HOSTS_LIST":
+ break;
+ case "TASKS_LIST":
+ break;
+ case "TASK_DETAILS":
+ this.destroyClipBoard();
+ break;
+ }
+
+ //entering level - do any setup here
+ switch (levelName) {
+ case "OPS_LIST":
+ this.gotoOps();
+ break;
+ case "HOSTS_LIST":
+ this.gotoHosts(context);
+ break;
+ case "TASKS_LIST":
+ this.gotoTasks(context);
+ break;
+ case "TASK_DETAILS":
+ this.goToTaskDetails(context);
+ break;
+ }
+
+ if (!this.get("controller.isBackgroundOperations")) {
+ var customControllersSwitchLevelMap = this.get('customControllersSwitchLevelMap');
+ var args = [].slice.call(arguments);
+ Em.tryInvoke(this, customControllersSwitchLevelMap[this.get('controller.dataSourceController.name')], args);
+ }
+ },
+
+ changeLevel: function(levelName) {
if (this.get("controller.isBackgroundOperations")) {
+ var dataSourceController = this.get('controller.dataSourceController');
var levelInfo = dataSourceController.get('levelInfo');
+
levelInfo.set('taskId', this.get('openedTaskId'));
levelInfo.set('requestId', this.get('controller.currentServiceId'));
levelInfo.set('name', levelName);
- if (levelName === 'HOSTS_LIST') {
- this.set('isLevelLoaded', dataSourceController.requestMostRecent());
- if (!isBackToLevel) {
- this.set('hostCategory', this.get('categories').findProperty('value', 'all'));
- }
- }
- else {
- if (levelName === 'TASK_DETAILS') {
- dataSourceController.requestMostRecent();
- this.set('isLevelLoaded', false);
- }
- else {
- if (levelName === 'REQUESTS_LIST') {
- if (!isBackToLevel) {
- this.set('serviceCategory', this.get('categories').findProperty('value', 'all'));
- }
- this.get('controller.hosts').clear();
- dataSourceController.requestMostRecent();
- }
- else {
- if (!isBackToLevel) {
- this.set('taskCategory', this.get('categories').findProperty('value', 'all'));
- }
- }
- }
- }
- }
- else {
- var customControllersSwitchLevelMap = this.get('customControllersSwitchLevelMap');
- Em.tryInvoke(this, customControllersSwitchLevelMap[dataSourceController.get('name')], args);
+ this.set('isLevelLoaded', dataSourceController.requestMostRecent());
}
+
+ this.set('currentLevel', levelName); //NOTE: setting this triggers levelDidChange() which updates the breadcrumbs
},
+ //This is triggered by changeLevel() -- (and probably some other things) --
+ //when "controller.dataSourceController.levelInfo.name" is set
levelDidChange: function() {
- var levelName = this.get('controller.dataSourceController.levelInfo.name'),
+ var levelName = this.get('currentLevel'),
self = this;
+ if (this.get("parentView.isOpen")) {
+ self.setBreadcrumbs(levelName);
+ }
+
if (levelName && this.get('isLevelLoaded')) {
Em.run.next(this, function() {
self.resizeHandler();
});
}
- }.observes('controller.dataSourceController.levelInfo.name', 'isLevelLoaded'),
-
+ }.observes('currentLevel', 'isLevelLoaded'),
popupIsOpenDidChange: function() {
- if (!this.get('isOpen')) {
- this.get('hostComponentLogs').clear();
+ const hostComponentLogs = this.get('hostComponentLogs');
+
+ if (!this.get('parentView.isOpen') && hostComponentLogs) {
+ hostComponentLogs.clear();
}
}.observes('parentView.isOpen'),
@@ -606,8 +687,7 @@ App.HostProgressPopupBodyView = App.TableView.extend({
Em.keys(this.get('parentView.detailedProperties')).forEach(function (key) {
dataSourceController.addObserver('taskInfo.' + this.get('parentView.detailedProperties')[key], this, 'updateTaskInfo');
}, this);
- }
- else {
+ } else {
dataSourceController.stopTaskPolling();
}
},
@@ -632,10 +712,6 @@ App.HostProgressPopupBodyView = App.TableView.extend({
* @method backToTaskList
*/
backToTaskList: function () {
- this.destroyClipBoard();
- this.set("openedTaskId", 0);
- this.set("parentView.isLogWrapHidden", true);
- this.set("parentView.isTaskListHidden", false);
this.switchLevel("TASKS_LIST", true);
},
@@ -645,27 +721,17 @@ App.HostProgressPopupBodyView = App.TableView.extend({
* @method backToHostList
*/
backToHostList: function () {
- this.set("parentView.isHostListHidden", false);
- this.set("parentView.isTaskListHidden", true);
- this.get("controller").set("popupHeaderName", this.get("controller.serviceName"));
- this.get("controller").set("operationInfo", this.get('controller.servicesInfo').findProperty('name', this.get('controller.serviceName')));
this.switchLevel("HOSTS_LIST", true);
},
/**
- * Onclick handler for button <-Services
+ * Onclick handler for button <-Operations
+ * TODO: This is still used somewhere outside the Background Operations heirarchy.
*
* @method backToServiceList
*/
backToServiceList: function () {
- this.get("controller").set("serviceName", "");
- this.set("parentView.isHostListHidden", true);
- this.set("parentView.isServiceListHidden", false);
- this.set("parentView.isTaskListHidden", true);
- this.set("parentView.isLogWrapHidden", true);
- this.set("hosts", null);
- this.get("controller").setBackgroundOperationHeader(false);
- this.switchLevel("REQUESTS_LIST", true);
+ this.switchLevel("OPS_LIST", true);
},
/**
@@ -689,27 +755,40 @@ App.HostProgressPopupBodyView = App.TableView.extend({
}
}.observes('parentView.isOpen', 'App.router.backgroundOperationsController.isShowMoreAvailable'),
+ gotoOps: function () {
+ this.get('controller.hosts').clear();
+ var dataSourceController = this.get('controller.dataSourceController');
+ dataSourceController.requestMostRecent();
+ this.get("controller").setBackgroundOperationHeader(false);
+
+ this.changeLevel("OPS_LIST");
+ this.get("parentView").switchView("OPS_LIST");
+ },
+
/**
- * Onclick handler for selected Service
+ * Onclick handler for selected Service (Operation)
*
* @param {{context: wrappedService}} event
* @method gotoHosts
*/
- gotoHosts: function (event) {
- this.get("controller").set("serviceName", event.context.get("name"));
- this.get("controller").set("currentServiceId", event.context.get("id"));
+ onOpClick: function(event) {
+ this.switchLevel("HOSTS_LIST", event.context);
+ },
+
+ gotoHosts: function (service) {
+ this.get("controller").set("serviceName", service.get("name"));
+ this.get("controller").set("currentServiceId", service.get("id"));
this.get("controller").set("currentHostName", null);
this.get("controller").onHostUpdate();
- this.switchLevel("HOSTS_LIST");
+ this.get('hostComponentLogs').clear();
+
+ this.changeLevel("HOSTS_LIST");
+
var servicesInfo = this.get("controller.hosts");
- this.set("controller.popupHeaderName", event.context.get("name"));
- this.set("controller.operationInfo", event.context);
+ this.set("controller.operationInfo", service);
//apply lazy loading on cluster with more than 100 nodes
this.set('hosts', servicesInfo.length > 100 ? servicesInfo.slice(0, 50) : servicesInfo);
- this.set("parentView.isServiceListHidden", true);
- this.set("parentView.isHostListHidden", false);
- this.set("parentView.isTaskListHidden", true);
$(".modal").scrollTop(0);
$(".modal-body").scrollTop(0);
if (servicesInfo.length > 100) {
@@ -718,9 +797,13 @@ App.HostProgressPopupBodyView = App.TableView.extend({
});
}
// Determine if source request schedule is present
- this.set('sourceRequestScheduleId', event.context.get("sourceRequestScheduleId"));
- this.set('sourceRequestScheduleCommand', event.context.get('contextCommand'));
+ this.set('sourceRequestScheduleId', service.get("sourceRequestScheduleId"));
+ this.set('sourceRequestScheduleCommand', service.get('contextCommand'));
this.refreshRequestScheduleInfo();
+
+ this.set('hostCategory', this.get('categories').findProperty('value', 'all'));
+
+ this.get("parentView").switchView("HOSTS_LIST");
},
/**
@@ -851,22 +934,34 @@ App.HostProgressPopupBodyView = App.TableView.extend({
* @param {{context: wrappedHost}} event
* @method gotoTasks
*/
- gotoTasks: function (event) {
+ onHostClick: function (event) {
+ this.switchLevel("TASKS_LIST", event.context);
+ },
+
+ gotoTasks: function (host) {
var tasksInfo = [];
- event.context.logTasks.forEach(function (_task) {
- tasksInfo.pushObject(this.get("controller").createTask(_task));
- }, this);
+
+ if (host.logTasks) {
+ host.logTasks.forEach(function (_task) {
+ tasksInfo.pushObject(this.get("controller").createTask(_task));
+ }, this);
+ }
+
if (tasksInfo.length) {
- this.get("controller").set("popupHeaderName", event.context.publicName);
- this.get("controller").set("currentHostName", event.context.publicName);
+ this.get("controller").set("currentHostName", host.publicName);
+ }
+
+ const currentHost = this.get("currentHost");
+ if (currentHost) {
+ currentHost.set("tasks", tasksInfo);
}
- this.switchLevel("TASKS_LIST");
- this.set('currentHost.tasks', tasksInfo);
- this.set("parentView.isHostListHidden", true);
- this.set("parentView.isTaskListHidden", false);
- this.preloadHostModel(Em.getWithDefault(event.context || {}, 'name', false));
+ this.preloadHostModel(Em.getWithDefault(host || {}, 'name', false));
+ this.set('taskCategory', this.get('categories').findProperty('value', 'all'));
$(".modal").scrollTop(0);
$(".modal-body").scrollTop(0);
+
+ this.changeLevel("TASKS_LIST");
+ this.get("parentView").switchView("TASKS_LIST");
},
/**
@@ -939,31 +1034,42 @@ App.HostProgressPopupBodyView = App.TableView.extend({
newDocument.close();
},
+ onTaskClick: function (event) {
+ this.switchLevel("TASK_DETAILS", event.context);
+ },
+
/**
* Onclick event for show task detail info
*
* @param {{context: wrappedTask}} event
- * @method toggleTaskLog
+ * @method goToTaskDetails
*/
- toggleTaskLog: function (event) {
- var taskInfo = event.context;
- this.set("parentView.isLogWrapHidden", false);
+ goToTaskDetails: function (taskInfo) {
const self = this;
var taskLogsClipboard = new Clipboard('.btn.copy-clipboard', {
text: function() {
return self.get('textAreaValue');
}
});
+
this.set('taskLogsClipboard', taskLogsClipboard);
if (this.get('isClipBoardActive')) {
this.destroyClipBoard();
}
- this.set("parentView.isHostListHidden", true);
- this.set("parentView.isTaskListHidden", true);
+
this.set('openedTaskId', taskInfo.id);
- this.switchLevel("TASK_DETAILS");
+
+ if (this.get("controller.isBackgroundOperations")) {
+ var dataSourceController = this.get('controller.dataSourceController');
+ dataSourceController.requestMostRecent();
+ this.set('isLevelLoaded', false);
+ }
+
$(".modal").scrollTop(0);
$(".modal-body").scrollTop(0);
+
+ this.changeLevel("TASK_DETAILS");
+ this.get("parentView").switchView("TASK_DETAILS");
},
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/test/controllers/global/background_operations_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/background_operations_test.js b/ambari-web/test/controllers/global/background_operations_test.js
index 4a8235c..cfadbf5 100644
--- a/ambari-web/test/controllers/global/background_operations_test.js
+++ b/ambari-web/test/controllers/global/background_operations_test.js
@@ -43,7 +43,7 @@ describe('App.BackgroundOperationsController', function () {
var tests = Em.A([
{
levelInfo: Em.Object.create({
- name: 'REQUESTS_LIST',
+ name: 'OPS_LIST',
requestId: null,
taskId: null,
sync: false
@@ -539,7 +539,7 @@ describe('App.BackgroundOperationsController', function () {
it("should return false when not on HOSTS_LIST level", function() {
controller.set('levelInfo', Em.Object.create({
- name: 'SERVICES_LIST'
+ name: 'OPS_LIST'
}));
expect(controller.isInitLoading()).to.be.false;
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/test/controllers/main/admin/highAvailability/progress_popup_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/admin/highAvailability/progress_popup_controller_test.js b/ambari-web/test/controllers/main/admin/highAvailability/progress_popup_controller_test.js
index 364d9b0..2742c44 100644
--- a/ambari-web/test/controllers/main/admin/highAvailability/progress_popup_controller_test.js
+++ b/ambari-web/test/controllers/main/admin/highAvailability/progress_popup_controller_test.js
@@ -343,6 +343,9 @@ describe('App.HighAvailabilityProgressPopupController', function () {
it("calculate data", function() {
var data = [
{
+ Requests: {
+ id: 1
+ },
tasks: [
{
Tasks: {
@@ -365,6 +368,7 @@ describe('App.HighAvailabilityProgressPopupController', function () {
controller.calculateHostsData(data);
expect(controller.get('services')).to.be.eql([
{
+ "id": 1,
"name": "popupTitle",
"hosts": [
{
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/test/utils/host_progress_popup_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/host_progress_popup_test.js b/ambari-web/test/utils/host_progress_popup_test.js
index dea2666..23ccf37 100644
--- a/ambari-web/test/utils/host_progress_popup_test.js
+++ b/ambari-web/test/utils/host_progress_popup_test.js
@@ -516,6 +516,11 @@ describe('App.HostPopup', function () {
});
+ describe("#initPopup", function() {
+ it("should reset the breadcrumbs", function() {
+ App.HostPopup.initPopup("rootBreadcrumb", Em.Object.create({ services: [] }));
-
+ expect(App.HostPopup.get("breadcrumbs")).to.deep.equal([{ label: "rootBreadcrumb" }]);
+ });
+ });
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/test/views/common/breadcrumbs_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/breadcrumbs_view_test.js b/ambari-web/test/views/common/breadcrumbs_view_test.js
index eff19f6..3e2fc17 100644
--- a/ambari-web/test/views/common/breadcrumbs_view_test.js
+++ b/ambari-web/test/views/common/breadcrumbs_view_test.js
@@ -34,6 +34,34 @@ describe('App.BreadcrumbItem', function () {
});
+ describe('#transition', function() {
+
+ beforeEach(function() {
+ sinon.stub(App.router, "route");
+
+ this.breadcrumb = App.BreadcrumbItem.create({
+ label: "label",
+ route: "route"
+ });
+ })
+
+ afterEach(function() {
+ App.router.route.restore();
+ })
+
+ it('App.router.route should be called', function() {
+ this.breadcrumb.transition();
+ expect(App.router.route.calledWith('main/' + this.breadcrumb.get("route"))).to.be.true;
+ })
+
+ it('action should be called when defined', function() {
+ this.breadcrumb.action = sinon.stub();
+ this.breadcrumb.transition();
+ expect(this.breadcrumb.action.called).to.be.true;
+ expect(App.router.route.called).to.be.false;
+ })
+ })
+
});
function getCurrentState(parentStateProps, currentStateProps) {
@@ -109,4 +137,4 @@ describe('App.BreadcrumbsView', function () {
});
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/38604db2/ambari-web/test/views/common/host_progress_popup_body_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/host_progress_popup_body_view_test.js b/ambari-web/test/views/common/host_progress_popup_body_view_test.js
index 5ccc024..7f905ea 100644
--- a/ambari-web/test/views/common/host_progress_popup_body_view_test.js
+++ b/ambari-web/test/views/common/host_progress_popup_body_view_test.js
@@ -17,324 +17,473 @@
*/
var App = require('app');
-var view;
+
+require("utils/host_progress_popup");
+require("views/common/modal_popup")
describe('App.HostProgressPopupBodyView', function () {
+ var controller;
beforeEach(function () {
- view = App.HostProgressPopupBodyView.create({
- controller: Em.Object.create({
- setSelectCount: Em.K,
- dataSourceController: Em.Object.create({}),
- setBackgroundOperationHeader: Em.K,
- hosts: []
+ controller = Em.Object.create({
+ setSelectCount: Em.K,
+ dataSourceController: Em.Object.create({
+ levelInfo: {},
+ requestMostRecent: Em.K
}),
- parentView: Em.Object.create()
+ refreshRequestScheduleInfo: Em.K,
+ setBackgroundOperationHeader: Em.K,
+ onHostUpdate: Em.K,
+ hosts: []
});
});
- describe('#switchLevel', function () {
-
- var map = App.HostProgressPopupBodyView.create().get('customControllersSwitchLevelMap');
-
- Object.keys(map).forEach(function (controllerName) {
- var methodName = map [controllerName];
- var levelName = 'REQUESTS_LIST';
+ describe('when not isBackgroundOperations', function() {
+ var view;
- beforeEach(function () {
- sinon.stub(view, methodName, Em.K);
- });
-
- afterEach(function () {
- view[methodName].restore();
- });
-
- it('should call ' + methodName, function () {
- view.set('controller.dataSourceController.name', controllerName);
- view.switchLevel(levelName);
- expect(view[methodName].args[0]).to.eql([levelName]);
+ beforeEach(function () {
+ view = App.HostProgressPopupBodyView.create({
+ controller: controller,
+ parentView: App.HostPopup.initPopup("serviceName", controller, false, 1)
});
-
});
- });
-
- describe('_determineRoleRelation', function() {
- var cases;
+ describe('#switchLevel when isBackgroundOperations is false', function () {
+ var map = App.HostProgressPopupBodyView.create().get('customControllersSwitchLevelMap');
- beforeEach(function() {
- sinon.stub(App.StackServiceComponent, 'find').returns([{componentName: 'DATANODE'}]);
- sinon.stub(App.StackService, 'find').returns([{serviceName: 'HDFS'}])
- });
+ Object.keys(map).forEach(function (controllerName) {
+ var methodName = map [controllerName];
+ var levelName = 'OPS_LIST';
- afterEach(function() {
- App.StackServiceComponent.find.restore();
- App.StackService.find.restore();
- });
+ beforeEach(function () {
+ sinon.stub(view, methodName, Em.K);
+ });
- cases = [
- {
- task: { role: 'HDFS_SERVICE_CHECK'},
- m: 'Role is HDFS_SERVICE_CHECK',
- e: {
- type: 'service',
- value: 'HDFS'
- }
- },
- {
- task: { role: 'DATANODE'},
- m: 'Role is DATANODE',
- e: {
- type: 'component',
- value: 'DATANODE'
- }
- },
- {
- task: { role: 'UNDEFINED'},
- m: 'Role is UNDEFINED',
- e: false
- }
- ];
-
- cases.forEach(function(test) {
- it(test.m, function() {
- view.reopen({
- currentHost: Em.Object.create({
- logTasks: [
- { Tasks: { id: 1, role: test.task.role }}
- ]
- })
+ afterEach(function () {
+ view[methodName].restore();
});
- var ret = view._determineRoleRelation(Em.Object.create({ id: 1 }));
- expect(ret).to.be.eql(test.e);
+ it('should call ' + methodName, function () {
+ view.set('controller.dataSourceController.name', controllerName);
+ view.switchLevel(levelName);
+ expect(view[methodName].args[0]).to.eql([levelName]);
+ });
});
});
- });
- describe('#didInsertElement', function () {
-
- beforeEach(function () {
- sinon.stub(view, 'updateHostInfo', Em.K);
- view.didInsertElement();
- });
-
- afterEach(function () {
- view.updateHostInfo.restore();
- });
-
- it('should display relevant info', function () {
- expect(view.updateHostInfo.calledOnce).to.be.true;
- });
-
- });
-
- describe('#preloadHostModel', function() {
- describe('When Log Search installed', function() {
+ describe('_determineRoleRelation', function() {
+ var cases;
beforeEach(function() {
- this.HostModelStub = sinon.stub(App.Host, 'find');
- this.isLogSearchInstalled = sinon.stub(view, 'get').withArgs('isLogSearchInstalled');
- this.logSearchSupported = sinon.stub(App, 'get').withArgs('supports.logSearch');
- this.updateCtrlStub = sinon.stub(App.router.get('updateController'), 'updateLogging');
+ sinon.stub(App.StackServiceComponent, 'find').returns([{componentName: 'DATANODE'}]);
+ sinon.stub(App.StackService, 'find').returns([{serviceName: 'HDFS'}])
});
- afterEach(function () {
- App.Host.find.restore();
- view.get.restore();
- App.get.restore();
- App.router.get('updateController').updateLogging.restore();
+ afterEach(function() {
+ App.StackServiceComponent.find.restore();
+ App.StackService.find.restore();
});
- [
- {
- hostName: 'host1',
- logSearchSupported: true,
- isLogSearchInstalled: true,
- requestFailed: false,
- hosts: [
- {
- hostName: 'host2'
- }
- ],
- e: {
- updateLoggingCalled: true
- },
- m: 'Host absent, log search installed and supported'
- },
+ cases = [
{
- hostName: 'host1',
- logSearchSupported: true,
- isLogSearchInstalled: true,
- requestFailed: false,
- hosts: [
- {
- hostName: 'host1'
- }
- ],
+ task: { role: 'HDFS_SERVICE_CHECK'},
+ m: 'Role is HDFS_SERVICE_CHECK',
e: {
- updateLoggingCalled: false
- },
- m: 'Host present, log search installed and supported'
+ type: 'service',
+ value: 'HDFS'
+ }
},
{
- hostName: 'host1',
- logSearchSupported: false,
- isLogSearchInstalled: true,
- requestFailed: false,
- hosts: [
- {
- hostName: 'host1'
- }
- ],
+ task: { role: 'DATANODE'},
+ m: 'Role is DATANODE',
e: {
- updateLoggingCalled: false
- },
- m: 'Host present, log search installed and support is off'
- },
- {
- hostName: 'host1',
- logSearchSupported: true,
- isLogSearchInstalled: true,
- requestFailed: true,
- hosts: [
- {
- hostName: 'host2'
- }
- ],
- e: {
- updateLoggingCalled: true
- },
- m: 'Host is absent, log search installed and supported, update request was failed'
+ type: 'component',
+ value: 'DATANODE'
+ }
},
{
- hostName: 'host1',
- logSearchSupported: true,
- isLogSearchInstalled: false,
- requestFailed: true,
- hosts: [
- {
- hostName: 'host2'
- }
- ],
- e: {
- updateLoggingCalled: false
- },
- m: 'Host is absent, log search not installed and supported'
+ task: { role: 'UNDEFINED'},
+ m: 'Role is UNDEFINED',
+ e: false
}
- ].forEach(function(test) {
+ ];
+
+ cases.forEach(function(test) {
+ it(test.m, function() {
+ view.reopen({
+ currentHost: Em.Object.create({
+ logTasks: [
+ { Tasks: { id: 1, role: test.task.role }}
+ ]
+ })
+ });
- it('hostInfoLoaded should be true on init', function() {
- expect(Em.get(view, 'hostInfoLoaded')).to.be.true;
+ var ret = view._determineRoleRelation(Em.Object.create({ id: 1 }));
+ expect(ret).to.be.eql(test.e);
});
+ });
+ });
- describe(test.m, function () {
-
- beforeEach(function () {
- this.HostModelStub.returns(test.hosts);
- this.isLogSearchInstalled.returns(test.isLogSearchInstalled);
- this.logSearchSupported.returns(test.logSearchSupported);
- if (test.requestFailed) {
- this.updateCtrlStub.returns($.Deferred().reject().promise());
- } else {
- this.updateCtrlStub.returns($.Deferred().resolve().promise());
- }
- Em.set(view, 'hostInfoLoaded', false);
- view.preloadHostModel(test.hostName);
- });
+ describe('#didInsertElement', function () {
- it('updateLogging call validation', function() {
- expect(App.router.get('updateController').updateLogging.called).to.be.equal(test.e.updateLoggingCalled);
- });
+ beforeEach(function () {
+ sinon.stub(view, 'updateHostInfo', Em.K);
+ view.didInsertElement();
+ });
+
+ afterEach(function () {
+ view.updateHostInfo.restore();
+ });
+
+ it('should display relevant info', function () {
+ expect(view.updateHostInfo.calledOnce).to.be.true;
+ });
+
+ });
+
+ describe('#preloadHostModel', function() {
+ describe('When Log Search installed', function() {
- it('in result hostInfoLoaded should be always true', function() {
+ beforeEach(function() {
+ this.HostModelStub = sinon.stub(App.Host, 'find');
+ this.isLogSearchInstalled = sinon.stub(view, 'get').withArgs('isLogSearchInstalled');
+ this.logSearchSupported = sinon.stub(App, 'get').withArgs('supports.logSearch');
+ this.updateCtrlStub = sinon.stub(App.router.get('updateController'), 'updateLogging');
+ });
+
+ afterEach(function () {
+ App.Host.find.restore();
+ view.get.restore();
+ App.get.restore();
+ App.router.get('updateController').updateLogging.restore();
+ });
+
+ [
+ {
+ hostName: 'host1',
+ logSearchSupported: true,
+ isLogSearchInstalled: true,
+ requestFailed: false,
+ hosts: [
+ {
+ hostName: 'host2'
+ }
+ ],
+ e: {
+ updateLoggingCalled: true
+ },
+ m: 'Host absent, log search installed and supported'
+ },
+ {
+ hostName: 'host1',
+ logSearchSupported: true,
+ isLogSearchInstalled: true,
+ requestFailed: false,
+ hosts: [
+ {
+ hostName: 'host1'
+ }
+ ],
+ e: {
+ updateLoggingCalled: false
+ },
+ m: 'Host present, log search installed and supported'
+ },
+ {
+ hostName: 'host1',
+ logSearchSupported: false,
+ isLogSearchInstalled: true,
+ requestFailed: false,
+ hosts: [
+ {
+ hostName: 'host1'
+ }
+ ],
+ e: {
+ updateLoggingCalled: false
+ },
+ m: 'Host present, log search installed and support is off'
+ },
+ {
+ hostName: 'host1',
+ logSearchSupported: true,
+ isLogSearchInstalled: true,
+ requestFailed: true,
+ hosts: [
+ {
+ hostName: 'host2'
+ }
+ ],
+ e: {
+ updateLoggingCalled: true
+ },
+ m: 'Host is absent, log search installed and supported, update request was failed'
+ },
+ {
+ hostName: 'host1',
+ logSearchSupported: true,
+ isLogSearchInstalled: false,
+ requestFailed: true,
+ hosts: [
+ {
+ hostName: 'host2'
+ }
+ ],
+ e: {
+ updateLoggingCalled: false
+ },
+ m: 'Host is absent, log search not installed and supported'
+ }
+ ].forEach(function(test) {
+
+ it('hostInfoLoaded should be true on init', function() {
expect(Em.get(view, 'hostInfoLoaded')).to.be.true;
});
+ describe(test.m, function () {
+
+ beforeEach(function () {
+ this.HostModelStub.returns(test.hosts);
+ this.isLogSearchInstalled.returns(test.isLogSearchInstalled);
+ this.logSearchSupported.returns(test.logSearchSupported);
+ if (test.requestFailed) {
+ this.updateCtrlStub.returns($.Deferred().reject().promise());
+ } else {
+ this.updateCtrlStub.returns($.Deferred().resolve().promise());
+ }
+ Em.set(view, 'hostInfoLoaded', false);
+ view.preloadHostModel(test.hostName);
+ });
+
+ it('updateLogging call validation', function() {
+ expect(App.router.get('updateController').updateLogging.called).to.be.equal(test.e.updateLoggingCalled);
+ });
+
+ it('in result hostInfoLoaded should be always true', function() {
+ expect(Em.get(view, 'hostInfoLoaded')).to.be.true;
+ });
+
+ });
});
});
});
- });
- describe("#resetState()", function () {
+ describe("#resetState()", function () {
- beforeEach(function() {
- sinon.stub(view.get('controller'), 'setBackgroundOperationHeader');
- sinon.stub(view, 'setOnStart');
- sinon.stub(view, 'rerender');
- sinon.stub(view, 'updateSelectView');
- });
+ beforeEach(function() {
+ sinon.stub(view.get('controller'), 'setBackgroundOperationHeader');
+ sinon.stub(view, 'setOnStart');
+ sinon.stub(view, 'rerender');
+ sinon.stub(view, 'updateSelectView');
+ });
- afterEach(function() {
- view.get('controller').setBackgroundOperationHeader.restore();
- view.setOnStart.restore();
- view.rerender.restore();
- view.updateSelectView.restore();
- });
+ afterEach(function() {
+ view.get('controller').setBackgroundOperationHeader.restore();
+ view.setOnStart.restore();
+ view.rerender.restore();
+ view.updateSelectView.restore();
+ });
- it("should set properties of parentView", function() {
- view.set('parentView.isOpen', true);
- expect(JSON.stringify(view.get('parentView'))).to.be.equal(JSON.stringify({
- "isOpen": true,
- "isLogWrapHidden": true,
- "isTaskListHidden": true,
- "isHostListHidden": true,
- "isServiceListHidden": false
- }));
- });
+ it("should set properties of parentView", function() {
+ view.set('parentView.isOpen', true);
+ expect(view.get('parentView.isOpen')).to.be.true;
+ expect(view.get('parentView.isLogWrapHidden')).to.be.true;
+ expect(view.get('parentView.isTaskListHidden')).to.be.true;
+ expect(view.get('parentView.isHostListHidden')).to.be.true;
+ expect(view.get('parentView.isServiceListHidden')).to.be.false;
+ });
- it("setBackgroundOperationHeader should be called", function() {
- view.set('parentView.isOpen', true);
- expect(view.get('controller').setBackgroundOperationHeader.calledWith(false)).to.be.true;
- });
+ it("setBackgroundOperationHeader should be called", function() {
+ view.set('parentView.isOpen', true);
+ expect(view.get('controller').setBackgroundOperationHeader.calledWith(false)).to.be.true;
+ });
+
+ it("controller.hosts should be empty", function() {
+ view.set('controller.hosts', [Em.Object.create({})]);
+ view.set('parentView.isOpen', true);
+ expect(view.get('controller.hosts')).to.be.empty;
+ });
+
+ it("setOnStart should be called", function() {
+ view.set('parentView.isOpen', true);
+ //console.log("setOnStart.callCount:", view.setOnStart.callCount);
+ expect(view.setOnStart.calledOnce, "calledOnce").to.be.true;
+ });
- it("controller.hosts should be empty", function() {
- view.set('controller.hosts', [Em.Object.create({})]);
- view.set('parentView.isOpen', true);
- expect(view.get('controller.hosts')).to.be.empty;
+ it("rerender should be called", function() {
+ view.set('parentView.isOpen', true);
+ expect(view.rerender.calledOnce).to.be.true;
+ });
});
- it("setOnStart should be called", function() {
- view.set('parentView.isOpen', true);
- expect(view.setOnStart.calledOnce).to.be.true;
+ describe('#goToTaskDetails', function () {
+
+ var task = {};
+
+ beforeEach(function() {
+ view.goToTaskDetails({context: task});
+ });
+
+ it('clipboard created', function () {
+ expect(view.get('taskLogsClipboard')).to.be.instanceOf(Clipboard);
+ });
+
});
- it("rerender should be called", function() {
- view.set('parentView.isOpen', true);
- expect(view.rerender.calledOnce).to.be.true;
+ describe('#destroyClipBoard', function () {
+
+ beforeEach(function () {
+ view.goToTaskDetails({context: {}});
+ sinon.spy(view.get('taskLogsClipboard'), 'destroy');
+ view.destroyClipBoard();
+ });
+
+ afterEach(function () {
+ view.get('taskLogsClipboard').destroy.restore();
+ });
+
+ it('should destroy clipboard', function () {
+ expect(view.get('taskLogsClipboard').destroy.calledOnce).to.be.true;
+ });
+
});
});
- describe('#toggleTaskLog', function () {
+ describe('when isBackgroundOperations', function() {
+ var view;
- var task = {};
+ beforeEach(function () {
+ view = App.HostProgressPopupBodyView.create({
+ controller: controller,
+ parentView: App.HostPopup.initPopup("", controller, true)
+ });
- beforeEach(function() {
- view.toggleTaskLog({context: task});
+ sinon.stub(view, "changeLevel");
});
- it('clipboard created', function () {
- expect(view.get('taskLogsClipboard')).to.be.instanceOf(Clipboard);
- });
+ describe("#switchLevel", function () {
+ it("makes Operations list visible", function() {
+ view.switchLevel("OPS_LIST");
+
+ expect(view.changeLevel.calledWith("OPS_LIST")).to.be.true;
+
+ expect(view.get("parentView.isLogWrapHidden")).to.be.true;
+ expect(view.get("parentView.isTaskListHidden")).to.be.true;
+ expect(view.get("parentView.isHostListHidden")).to.be.true;
+ expect(view.get("parentView.isServiceListHidden")).to.be.false;
+ });
+
+ it("makes Hosts list visible", function() {
+ view.switchLevel("HOSTS_LIST", Em.Object.create());
+
+ expect(view.changeLevel.calledWith("HOSTS_LIST")).to.be.true;
+
+ expect(view.get("parentView.isLogWrapHidden")).to.be.true;
+ expect(view.get("parentView.isTaskListHidden")).to.be.true;
+ expect(view.get("parentView.isHostListHidden")).to.be.false;
+ expect(view.get("parentView.isServiceListHidden")).to.be.true;
+ });
+ it("makes Tasks list visible", function() {
+ view.switchLevel("TASKS_LIST", Em.Object.create());
+
+ expect(view.changeLevel.calledWith("TASKS_LIST")).to.be.true;
+
+ expect(view.get("parentView.isLogWrapHidden")).to.be.true;
+ expect(view.get("parentView.isTaskListHidden")).to.be.false;
+ expect(view.get("parentView.isHostListHidden")).to.be.true;
+ expect(view.get("parentView.isServiceListHidden")).to.be.true;
+ });
+
+ it("makes Task Details visible", function() {
+ view.switchLevel("TASK_DETAILS", Em.Object.create());
+
+ expect(view.changeLevel.calledWith("TASK_DETAILS")).to.be.true;
+
+ expect(view.get("parentView.isLogWrapHidden")).to.be.false;
+ expect(view.get("parentView.isTaskListHidden")).to.be.true;
+ expect(view.get("parentView.isHostListHidden")).to.be.true;
+ expect(view.get("parentView.isServiceListHidden")).to.be.true;
+ });
+ });
});
- describe('#destroyClipBoard', function () {
+ describe("#changeLevel", function() {
+ var view;
+ var controller;
beforeEach(function () {
- view.toggleTaskLog({context: {}});
- sinon.spy(view.get('taskLogsClipboard'), 'destroy');
- view.destroyClipBoard();
+ controller = Em.Object.create({
+ setSelectCount: Em.K,
+ dataSourceController: Em.Object.create({
+ levelInfo: {},
+ requestMostRecent: Em.K
+ }),
+ refreshRequestScheduleInfo: Em.K,
+ setBackgroundOperationHeader: Em.K,
+ onHostUpdate: Em.K,
+ hosts: [],
+ breadcrumbs: null,
+ rootBreadcrumb: { label: "rootBreadcrumb" },
+ serviceName: "serviceName",
+ currentHostName: "currentHostName"
+ });
+
+ view = App.HostProgressPopupBodyView.create({
+ controller: controller,
+ parentView: Em.Object.create({ isOpen: true })
+ });
});
- afterEach(function () {
- view.get('taskLogsClipboard').destroy.restore();
+ it("sets correct breadcrumbs for Operations view", function() {
+ view.changeLevel("OPS_LIST");
+
+ var breadcrumbs = view.get("controller.breadcrumbs");
+
+ expect(breadcrumbs.length).to.equal(1);
+ expect(breadcrumbs[0].label).to.equal("rootBreadcrumb");
+ expect(breadcrumbs[0].action).to.be.a("function");
});
- it('should destroy clipboard', function () {
- expect(view.get('taskLogsClipboard').destroy.calledOnce).to.be.true;
+ it("sets correct breadcrumbs for Hosts view", function() {
+ view.changeLevel("HOSTS_LIST");
+
+ var breadcrumbs = view.get("controller.breadcrumbs");
+
+ expect(breadcrumbs.length).to.equal(2);
+ expect(breadcrumbs[0].label).to.equal("rootBreadcrumb");
+ expect(breadcrumbs[0].action).to.be.a("function");
+ expect(breadcrumbs[1].label).to.equal("serviceName");
+ expect(breadcrumbs[1].action).to.be.a("function");
});
- });
+ it("sets correct breadcrumbs for Tasks view", function() {
+ view.changeLevel("TASKS_LIST");
+
+ var breadcrumbs = view.get("controller.breadcrumbs");
+
+ expect(breadcrumbs.length).to.equal(3);
+ expect(breadcrumbs[0].label).to.equal("rootBreadcrumb");
+ expect(breadcrumbs[0].action).to.be.a("function");
+ expect(breadcrumbs[1].label).to.equal("serviceName");
+ expect(breadcrumbs[1].action).to.be.a("function");
+ expect(breadcrumbs[2].label).to.equal("currentHostName");
+ expect(breadcrumbs[2].action).to.be.a("function");
+ });
+ it("sets correct breadcrumbs for Tasks view", function() {
+ view.changeLevel("TASK_DETAILS");
+
+ var breadcrumbs = view.get("controller.breadcrumbs");
+
+ expect(breadcrumbs.length).to.equal(4);
+ expect(breadcrumbs[0].label).to.equal("rootBreadcrumb");
+ expect(breadcrumbs[0].action).to.be.a("function");
+ expect(breadcrumbs[1].label).to.equal("serviceName");
+ expect(breadcrumbs[1].action).to.be.a("function");
+ expect(breadcrumbs[2].label).to.equal("currentHostName");
+ expect(breadcrumbs[2].action).to.be.a("function");
+ expect(breadcrumbs[3].itemView).to.be.a("function");
+ });
+ });
});