| /** |
| * 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'); |
| var date = require('utils/date/date'); |
| var dataUtils = require('utils/data_manipulation'); |
| |
| /** |
| * Host information shown in the operations popup |
| * @typedef {Em.Object} wrappedHost |
| * @property {string} name |
| * @property {string} publicName |
| * @property {string} displayName |
| * @property {number} progress |
| * @property {boolean} isInProgress |
| * @property {string} serviceName |
| * @property {string} status |
| * @property {number} isVisible |
| * @property {string} icon |
| * @property {string} barColor |
| * @property {string} barWidth |
| */ |
| |
| /** |
| * Task information shown in the operations popup |
| * @typedef {Em.Object} wrappedTask |
| * @property {string} id |
| * @property {string} hostName |
| * @property {string} command |
| * @property {string} commandDetail |
| * @property {string} status |
| * @property {string} role |
| * @property {string} stderr |
| * @property {string} stdout |
| * @property {number} request_id |
| * @property {boolean} isVisible |
| * @property {string} startTime |
| * @property {string} duration |
| * @property {string} icon |
| */ |
| |
| /** |
| * Service information shown in the operations popup |
| * @typedef {Em.Object} wrappedService |
| * @property {string} id |
| * @property {string} displayName |
| * @property {string} progress |
| * @property {string} status |
| * @property {string} userName |
| * @property {boolean} isRunning |
| * @property {string} name |
| * @property {boolean} isVisible |
| * @property {string} startTime |
| * @property {string} duration |
| * @property {string} icon |
| * @property {string} barColor |
| * @property {boolean} isInProgress |
| * @property {string} barWidth |
| * @property {number} sourceRequestScheduleId |
| * @property {string} contextCommand |
| */ |
| |
| /** |
| * App.HostPopup is for the popup that shows up upon clicking already-performed or currently-in-progress operations |
| * Allows to abort executing operations |
| * |
| * @type {Em.Object} |
| * @class {HostPopup} |
| */ |
| App.HostPopup = Em.Object.create({ |
| |
| name: 'hostPopup', |
| |
| /** |
| * @type {object[]} |
| */ |
| servicesInfo: [], |
| |
| /** |
| * @type {wrappedHost[]} |
| */ |
| hosts: [], |
| |
| /** |
| * @type {?object[]} |
| */ |
| inputData: null, |
| |
| /** |
| * @type {string} |
| */ |
| serviceName: '', |
| |
| /** |
| * @type {?Number} |
| */ |
| currentServiceId: null, |
| |
| /** |
| * @type {?Number} |
| */ |
| previousServiceId: null, |
| |
| /** |
| * @type {string} |
| */ |
| popupHeaderName: '', |
| |
| //This is what the breadcrumbs will be reset to every time the modal is opened. |
| rootBreadcrumb: null, |
| |
| /** |
| * @type {object[]} |
| */ |
| breadcrumbs: [], |
| |
| operationInfo: null, |
| |
| /** |
| * @type {?App.Controller} |
| */ |
| dataSourceController: null, |
| |
| /** |
| * @type {bool} |
| */ |
| isBackgroundOperations: false, |
| |
| /** |
| * @type {?string} |
| */ |
| currentHostName: null, |
| |
| /** |
| * @type {?App.ModalPopup} |
| */ |
| isPopup: null, |
| |
| /** |
| * @type {object} |
| */ |
| detailedProperties: { |
| stdout: 'stdout', |
| stderr: 'stderr', |
| outputLog: 'output_log', |
| errorLog: 'error_log' |
| }, |
| |
| /** |
| * @type {object} |
| */ |
| barColorMap: { |
| 'FAILED': 'progress-bar-danger', |
| 'ABORTED': 'progress-bar-warning', |
| 'TIMEDOUT': 'progress-bar-warning', |
| 'IN_PROGRESS': 'progress-bar-info', |
| 'COMPLETED': 'progress-bar-success' |
| }, |
| |
| /** |
| * map to get css class with styles by service status |
| * |
| * @type {object} |
| */ |
| statusesStyleMap: { |
| 'FAILED': ['FAILED', 'icon-exclamation-sign', 'progress-bar-danger', false], |
| 'ABORTED': ['ABORTED', 'glyphicon glyphicon-minus', 'progress-bar-warning', false], |
| 'TIMEDOUT': ['TIMEDOUT', 'glyphicon glyphicon-time', 'progress-bar-warning', false], |
| 'IN_PROGRESS': ['IN_PROGRESS', 'icon-cogs', 'progress-bar-info', true], |
| 'COMPLETED': ['SUCCESS', 'glyphicon glyphicon-ok', 'progress-bar-success', false] |
| }, |
| |
| /** |
| * View with "Abort Request"-button |
| * |
| * @type {Em.View} |
| */ |
| abortIcon: Em.View.extend({ |
| tagName: 'a', |
| classNames: ['action', 'abort-icon'], |
| template: Em.Handlebars.compile('<span class="icon icon-remove-circle"></span>'), |
| click: function () { |
| this.get('controller').abortRequest(this.get('servicesInfo')); |
| return false; |
| }, |
| didInsertElement: function () { |
| App.tooltip($(this.get('element')), { |
| placement: "top", |
| title: Em.I18n.t('hostPopup.bgop.abortRequest.title') |
| }); |
| }, |
| willDestroyElement: function () { |
| $(this.get('element')).tooltip('destroy'); |
| } |
| }), |
| |
| /** |
| * View with status icon (and tooltip on it) |
| * |
| * @type {Em.View} |
| */ |
| statusIcon: Em.View.extend({ |
| tagName: 'i', |
| classNames: ["service-status"], |
| classNameBindings: ['servicesInfo.status', 'servicesInfo.icon', 'additionalClass'], |
| attributeBindings: ['data-original-title'], |
| 'data-original-title': function () { |
| return this.get('servicesInfo.status'); |
| }.property('servicesInfo.status'), |
| didInsertElement: function () { |
| App.tooltip($(this.get('element'))); |
| }, |
| willDestroyElement: function () { |
| $(this.get('element')).tooltip('destroy'); |
| } |
| }), |
| |
| /** |
| * Determines if background operation can be aborted depending on its status |
| * |
| * @param status |
| * @returns {boolean} |
| */ |
| isAbortableByStatus: function (status) { |
| var statuses = this.get('statusesStyleMap'); |
| return !Em.keys(statuses).contains(status) || status === 'IN_PROGRESS'; |
| }, |
| |
| /** |
| * Send request to abort operation |
| * |
| * @method abortRequest |
| */ |
| abortRequest: function (serviceInfo) { |
| var requestName = serviceInfo.get('name'); |
| var self = this; |
| App.showConfirmationPopup(function () { |
| serviceInfo.set('isAbortable', false); |
| return App.ajax.send({ |
| name: 'background_operations.abort_request', |
| sender: self, |
| data: { |
| requestId: serviceInfo.get('id'), |
| requestName: requestName, |
| serviceInfo: serviceInfo |
| }, |
| success: 'abortRequestSuccessCallback', |
| error: 'abortRequestErrorCallback' |
| }); |
| }, Em.I18n.t('hostPopup.bgop.abortRequest.confirmation.body').format(requestName)); |
| return false; |
| }, |
| |
| /** |
| * Method called on successful sending request to abort operation |
| * |
| * @return {App.ModalPopup} |
| * @method abortRequestSuccessCallback |
| */ |
| abortRequestSuccessCallback: function (response, request, data) { |
| return App.ModalPopup.show({ |
| header: Em.I18n.t('hostPopup.bgop.abortRequest.modal.header'), |
| encodeBody: false, |
| body: Em.I18n.t('hostPopup.bgop.abortRequest.modal.body').format(data.requestName), |
| secondary: null |
| }); |
| }, |
| |
| /** |
| * Method called on unsuccessful sending request to abort operation |
| * |
| * @method abortRequestErrorCallback |
| */ |
| abortRequestErrorCallback: function (xhr, textStatus, error, opt, data) { |
| data.serviceInfo.set('isAbortable', this.isAbortableByStatus(data.serviceInfo.status)); |
| App.ajax.defaultErrorHandler(xhr, opt.url, 'PUT', xhr.status); |
| }, |
| |
| /** |
| * Entering point of this component |
| * |
| * @param {String} serviceName |
| * @param {Object} controller |
| * @param {Boolean} isBackgroundOperations |
| * @param {Integer} requestId |
| * @method initPopup |
| */ |
| initPopup: function (serviceName, controller, isBackgroundOperations, requestId) { |
| if (App.get('isClusterUser')) return; |
| |
| if (!isBackgroundOperations) { |
| this.clearHostPopup(); |
| 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: controller.get("services") |
| }); |
| |
| if (isBackgroundOperations) { |
| this.onServiceUpdate(); |
| } else { |
| this.onHostUpdate(); |
| } |
| |
| return this.createPopup(); |
| }, |
| |
| /** |
| * clear info popup data |
| * |
| * @method clearHostPopup |
| */ |
| clearHostPopup: function () { |
| this.setProperties({ |
| servicesInfo: [], |
| host: null, |
| inputData: null, |
| serviceName: '', |
| currentServiceId: null, |
| previousServiceId: null, |
| popupHeaderName: '', |
| dataSourceController: null, |
| currentHostName: null |
| }); |
| if(this.get('isPopup')) { |
| this.get('isPopup').remove(); |
| } |
| }, |
| |
| /** |
| * Depending on tasks status |
| * |
| * @param {object[]} tasks |
| * @return {*[]} [Status, Icon type, Progressbar color, is IN_PROGRESS] |
| * @method getStatus |
| */ |
| getStatus: function (tasks) { |
| var isCompleted = true; |
| var tasksLength = tasks.length; |
| for (var i = 0; i < tasksLength; i++) { |
| var taskStatus = tasks[i].Tasks.status; |
| if (taskStatus !== 'COMPLETED') { |
| isCompleted = false; |
| } |
| if (taskStatus === 'FAILED') { |
| return ['FAILED', 'icon-exclamation-sign', 'progress-bar-danger', false]; |
| } |
| if (taskStatus === 'ABORTED') { |
| return ['ABORTED', 'glyphicon glyphicon-minus', 'progress-bar-warning', false]; |
| } |
| if (taskStatus === 'TIMEDOUT') { |
| return ['TIMEDOUT', 'glyphicon glyphicon-time', 'progress-bar-warning', false]; |
| } |
| if (taskStatus === 'IN_PROGRESS') { |
| return ['IN_PROGRESS', 'icon-cogs', 'progress-bar-info', true] |
| } |
| } |
| if (isCompleted) { |
| return ['SUCCESS', 'glyphicon glyphicon-ok', 'progress-bar-success', false]; |
| } |
| return ['PENDING', 'glyphicon glyphicon-cog', 'progress-bar-info', true]; |
| }, |
| |
| /** |
| * Progress of host or service depending on tasks status |
| * If no tasks, progress is 0 |
| * |
| * @param {?object[]} tasks |
| * @return {Number} percent of completion |
| * @method getProgress |
| */ |
| getProgress: function (tasks) { |
| if (!tasks || !tasks.length) { |
| return 0; |
| } |
| |
| var groupedByStatus = dataUtils.groupPropertyValues(tasks, 'Tasks.status'); |
| |
| var completedActions = Em.getWithDefault(groupedByStatus, 'COMPLETED.length', 0) + |
| Em.getWithDefault(groupedByStatus, 'FAILED.length', 0) + |
| Em.getWithDefault(groupedByStatus, 'ABORTED.length', 0) + |
| Em.getWithDefault(groupedByStatus, 'TIMEDOUT.length', 0); |
| var queuedActions = Em.getWithDefault(groupedByStatus, 'QUEUED.length', 0); |
| var inProgressActions = Em.getWithDefault(groupedByStatus, 'IN_PROGRESS.length', 0); |
| |
| return Math.ceil((queuedActions * 0.09 + inProgressActions * 0.35 + completedActions ) / tasks.length * 100); |
| }, |
| |
| /** |
| * Count number of operations for select box options |
| * |
| * @param {?Object[]} obj |
| * @param {progressPopupCategoryObject[]} categories |
| * @method setSelectCount |
| */ |
| setSelectCount: function (obj, categories) { |
| if (!obj) { |
| return; |
| } |
| var groupedByStatus = dataUtils.groupPropertyValues(obj, 'status'); |
| |
| categories.findProperty("value", 'all').set("count", obj.length); |
| categories.findProperty("value", 'pending').set("count", Em.getWithDefault(groupedByStatus, 'pending.length', 0) + Em.getWithDefault(groupedByStatus, 'queued.length', 0)); |
| categories.findProperty("value", 'in_progress').set("count", Em.getWithDefault(groupedByStatus, 'in_progress.length', 0)); |
| categories.findProperty("value", 'failed').set("count", Em.getWithDefault(groupedByStatus, 'failed.length', 0)); |
| categories.findProperty("value", 'completed').set("count", Em.getWithDefault(groupedByStatus, 'success.length', 0) + Em.getWithDefault(groupedByStatus, 'completed.length', 0)); |
| categories.findProperty("value", 'aborted').set("count", Em.getWithDefault(groupedByStatus, 'aborted.length', 0)); |
| categories.findProperty("value", 'timedout').set("count", Em.getWithDefault(groupedByStatus, 'timedout.length', 0)); |
| }, |
| |
| /** |
| * For Background operation popup calculate number of running Operations, and set popup header |
| * |
| * @param {bool} isServiceListHidden |
| * @method setBackgroundOperationHeader |
| */ |
| setBackgroundOperationHeader: function (isServiceListHidden) { |
| if (this.get('isBackgroundOperations') && !isServiceListHidden) { |
| var numRunning = App.router.get('backgroundOperationsController.runningOperationsCount'); |
| this.set("popupHeaderName", numRunning + Em.I18n.t('hostPopup.header.postFix').format(numRunning === 1 ? "" : "s")); |
| } |
| }, |
| |
| /** |
| * Create services obj data structure for popup |
| * Set data for services |
| * |
| * @param {bool} isServiceListHidden |
| * @method onServiceUpdate |
| */ |
| onServiceUpdate: function (isServiceListHidden) { |
| 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); |
| var existedService = servicesInfo.findProperty('id', id); |
| updatedService = existedService; |
| if (existedService) { |
| updatedService = this.updateService(existedService, service); |
| } |
| else { |
| updatedService = this.createService(service); |
| servicesInfo.insertAt(index, updatedService); |
| } |
| updatedService.set('isAbortable', App.isAuthorized('SERVICE.START_STOP') && this.isAbortableByStatus(service.status)); |
| }, this); |
| } |
| |
| this.removeOldServices(servicesInfo, currentServices); |
| this.setBackgroundOperationHeader(isServiceListHidden); |
| }, |
| |
| /** |
| * Create service object from transmitted data |
| * |
| * @param {object} service |
| * @return {wrappedService} |
| * @method createService |
| */ |
| createService: function (service) { |
| var statuses = this.get('statusesStyleMap'); |
| var pendingStatus = ['PENDING', 'glyphicon glyphicon-cog', 'progress-bar-info', true]; |
| var status = statuses[service.status] || pendingStatus; |
| return Em.Object.create({ |
| id: service.id, |
| displayName: service.displayName, |
| progress: service.progress, |
| status: App.format.taskStatus(status[0]), |
| userName: service.userName, |
| isRunning: service.isRunning, |
| name: service.name, |
| isVisible: true, |
| startTime: date.startTime(service.startTime), |
| duration: date.durationSummary(service.startTime, service.endTime), |
| icon: status[1], |
| barColor: status[2], |
| isInProgress: status[3], |
| barWidth: "width:" + service.progress + "%;", |
| sourceRequestScheduleId: service.sourceRequestScheduleId, |
| contextCommand: service.contextCommand |
| }); |
| }, |
| |
| /** |
| * Update properties of existed service with new data |
| * |
| * @param {wrappedService} service |
| * @param {object} newData |
| * @returns {wrappedService} |
| * @method updateService |
| */ |
| updateService: function (service, newData) { |
| var statuses = this.get('statusesStyleMap'); |
| var pendingStatus = ['PENDING', 'glyphicon glyphicon-cog', 'progress-bar-info', true]; |
| var status = statuses[newData.status] || pendingStatus; |
| return service.setProperties({ |
| progress: newData.progress, |
| status: App.format.taskStatus(status[0]), |
| userName: newData.userName, |
| isRunning: newData.isRunning, |
| startTime: date.startTime(newData.startTime), |
| duration: date.durationSummary(newData.startTime, newData.endTime), |
| icon: status[1], |
| barColor: status[2], |
| isInProgress: status[3], |
| barWidth: "width:" + newData.progress + "%;", |
| sourceRequestScheduleId: newData.get && newData.get('sourceRequestScheduleId'), |
| contextCommand: newData.get && newData.get('contextCommand') |
| }); |
| }, |
| |
| /** |
| * remove old requests |
| * as API returns 10, or 20 , or 30 ...etc latest request, the requests that absent in response should be removed |
| * |
| * @param {wrappedService[]} services |
| * @param {number[]} currentServicesIds |
| * @method removeOldServices |
| */ |
| removeOldServices: function (services, currentServicesIds) { |
| for (var i = 0, l = services.length; i < l; i++) { |
| if (!currentServicesIds.contains(services[i].id)) { |
| services.splice(i, 1); |
| i--; |
| l--; |
| } |
| } |
| }, |
| |
| /** |
| * Wrap task as Ember-object |
| * |
| * @param {Object} _task |
| * @return {wrappedTask} |
| * @method createTask |
| */ |
| createTask: function (_task) { |
| return Em.Object.create({ |
| id: _task.Tasks.id, |
| hostName: _task.Tasks.host_name, |
| command: _task.Tasks.command.toLowerCase() === 'service_check' ? '' : _task.Tasks.command.toLowerCase(), |
| commandDetail: App.format.commandDetail(_task.Tasks.command_detail, _task.Tasks.request_inputs, _task.Tasks.ops_display_name), |
| status: App.format.taskStatus(_task.Tasks.status), |
| role: App.format.role(_task.Tasks.role, false), |
| stderr: _task.Tasks.stderr, |
| stdout: _task.Tasks.stdout, |
| request_id: _task.Tasks.request_id, |
| isVisible: true, |
| startTime: date.startTime(_task.Tasks.start_time), |
| duration: date.durationSummary(_task.Tasks.start_time, _task.Tasks.end_time), |
| icon: function () { |
| var statusIconMap = { |
| 'pending': 'glyphicon glyphicon-cog', |
| 'queued': 'glyphicon glyphicon-cog', |
| 'in_progress': 'icon-cogs', |
| 'completed': 'glyphicon glyphicon-ok', |
| 'failed': 'icon-exclamation-sign', |
| 'aborted': 'glyphicon glyphicon-minus', |
| 'timedout': 'glyphicon glyphicon-time' |
| }; |
| return statusIconMap[this.get('status')] || 'glyphicon glyphicon-cog'; |
| }.property('status') |
| }); |
| }, |
| |
| /** |
| * Create hosts and tasks data structure for popup |
| * Set data for hosts and tasks |
| * |
| * @method onHostUpdate |
| */ |
| onHostUpdate: function () { |
| var self = this; |
| if (this.get("inputData")) { |
| var hostsMap = this._getHostsMap(); |
| var existedHosts = self.get('hosts'); |
| |
| if (existedHosts && existedHosts.length && this.get('currentServiceId') === this.get('previousServiceId')) { |
| this._processingExistingHostsWithSameService(hostsMap); |
| } else { |
| var hostsArr = this._hostMapProcessing(hostsMap); |
| hostsArr = hostsArr.sortProperty('name'); |
| hostsArr.setEach("serviceName", this.get("serviceName")); |
| self.set("hosts", hostsArr); |
| self.set('previousServiceId', this.get('currentServiceId')); |
| } |
| } |
| var operation = this.get('servicesInfo').findProperty('id', this.get('currentServiceId')); |
| this.set('operationInfo', !operation || operation && operation.get('progress') === 100 ? null : operation); |
| }, |
| |
| /** |
| * Generate hosts map for further processing <code>inputData</code> |
| * |
| * @returns {object} |
| * @private |
| * @method _getHostsMap |
| */ |
| _getHostsMap: function () { |
| 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 { |
| if (this.get("serviceName")) { |
| //hosts popup for Wizards |
| hostsData = inputData.findProperty("name", this.get("serviceName")); |
| } |
| } |
| |
| if (hostsData) { |
| if (hostsData.hostsMap) { |
| //hosts data come from Background Operations as object map |
| hostsMap = hostsData.hostsMap; |
| } else { |
| if (hostsData.hosts) { |
| //hosts data come from Wizard as array |
| hostsMap = hostsData.hosts.toMapByProperty('name'); |
| } |
| } |
| } |
| |
| return hostsMap; |
| }, |
| |
| /** |
| * |
| * @param {object} hostsMap |
| * @returns {wrappedHost[]} |
| * @private |
| * @method _hostMapProcessing |
| */ |
| _hostMapProcessing: function (hostsMap) { |
| var self = this; |
| var hostsArr = []; |
| for (var hostName in hostsMap) { |
| if (!hostsMap.hasOwnProperty(hostName)) { |
| continue; |
| } |
| var _host = hostsMap[hostName]; |
| var tasks = _host.logTasks; |
| var hostInfo = Em.Object.create({ |
| name: hostName, |
| publicName: _host.publicName, |
| displayName: Em.computed.truncate('name', 43, 40), |
| progress: 0, |
| status: App.format.taskStatus("PENDING"), |
| serviceName: _host.serviceName, |
| isVisible: true, |
| icon: "glyphicon glyphicon-cog", |
| barColor: "progress-bar-info", |
| barWidth: "width:0%;" |
| }); |
| |
| if (tasks.length) { |
| tasks = tasks.sortProperty('Tasks.id'); |
| var hostStatus = self.getStatus(tasks); |
| var hostProgress = self.getProgress(tasks); |
| hostInfo.setProperties({ |
| status: App.format.taskStatus(hostStatus[0]), |
| icon: hostStatus[1], |
| barColor: hostStatus[2], |
| isInProgress: hostStatus[3], |
| progress: hostProgress, |
| barWidth: "width:" + hostProgress + "%;" |
| }); |
| } |
| hostInfo.set('logTasks', tasks); |
| hostsArr.push(hostInfo); |
| } |
| return hostsArr; |
| }, |
| |
| /** |
| * |
| * @param {object} hostsMap |
| * @private |
| * @method _processingExistingHostsWithSameService |
| */ |
| _processingExistingHostsWithSameService: function (hostsMap) { |
| var self = this; |
| 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') || |
| newHostInfo.isModified || |
| 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], |
| barColor: hostStatus[2], |
| isInProgress: hostStatus[3], |
| progress: hostProgress, |
| 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 { |
| existTasks.pushObject(this.createTask(_task)); |
| } |
| }, this); |
| } |
| } |
| }, this); |
| }, |
| |
| /** |
| * Custom processing for "Rebalance HDFS"-task |
| * |
| * @param {object} task |
| * @param {object} existTask |
| * @returns {object} |
| * @private |
| * @method _handleRebalanceHDFS |
| */ |
| _handleRebalanceHDFS: function (task, existTask) { |
| var barColorMap = this.get('barColorMap'); |
| var isRebalanceHDFSTask = task.Tasks.command === 'CUSTOM_COMMAND' && task.Tasks.custom_command_name === 'REBALANCEHDFS'; |
| existTask.set('isRebalanceHDFSTask', isRebalanceHDFSTask); |
| if (isRebalanceHDFSTask) { |
| var structuredOut = task.Tasks.structured_out || {}; |
| var status = task.Tasks.status; |
| existTask.setProperties({ |
| dataMoved: structuredOut.dataMoved || '0', |
| dataLeft: structuredOut.dataLeft || '0', |
| dataBeingMoved: structuredOut.dataBeingMoved || '0', |
| barColor: barColorMap[status], |
| isInProgress: status === 'IN_PROGRESS', |
| isNotComplete: ['QUEUED', 'IN_PROGRESS'].contains(status), |
| completionProgressStyle: 'width:' + (structuredOut.completePercent || 0) * 100 + '%;', |
| command: task.Tasks.command, |
| custom_command_name: task.Tasks.custom_command_name |
| }); |
| } |
| return existTask; |
| }, |
| |
| /** |
| * Show popup |
| * |
| * @return {App.ModalPopup} PopupObject For testing purposes |
| */ |
| createPopup: function () { |
| var self = this; |
| var isBackgroundOperations = this.get('isBackgroundOperations'); |
| |
| 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, |
| |
| /** |
| * no need to track is it loaded when popup contain only list of hosts |
| * @type {bool} |
| */ |
| isLoaded: !isBackgroundOperations, |
| |
| /** |
| * is BG-popup opened |
| * @type {bool} |
| */ |
| isOpen: false, |
| |
| /** |
| * @type {object} |
| */ |
| detailedProperties: self.get('detailedProperties'), |
| |
| isVisible: function() { |
| return !(App.get('isClusterUser') && isBackgroundOperations); |
| }.property('App.isClusterUser'), |
| |
| didInsertElement: function () { |
| this._super(); |
| this.set('isOpen', true); |
| }, |
| |
| /** |
| * @type {Em.View} |
| */ |
| 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}}' + |
| '{{view controller.abortIcon servicesInfoBinding="controller.operationInfo"}}' + |
| '{{/if}}{{/unless}}') |
| }), |
| |
| /** |
| * @type {Em.View} |
| */ |
| footerClass: Em.View.extend({ |
| classNames: ["modal-footer"], |
| templateName: require('templates/common/host_progress_popup_footer') |
| }), |
| |
| /** |
| * @type {String[]} |
| */ |
| classNames: ['common-modal-wrapper', 'host-progress-popup', 'full-height-modal'], |
| modalDialogClasses: ['modal-lg'], |
| |
| /** |
| * Auto-display BG-popup |
| * |
| * @type {bool} |
| */ |
| isNotShowBgChecked: null, |
| |
| /** |
| * Save user pref about auto-display BG-popup |
| * |
| * @method updateNotShowBgChecked |
| */ |
| updateNotShowBgChecked: function () { |
| var curVal = !this.get('isNotShowBgChecked'); |
| if (!App.get('testMode')) { |
| App.router.get('userSettingsController').postUserPref('show_bg', curVal); |
| } |
| }.observes('isNotShowBgChecked'), |
| |
| autoHeight: false, |
| |
| /** |
| * @method closeModelPopup |
| */ |
| closeModelPopup: function () { |
| this.set('isOpen', false); |
| if (isBackgroundOperations) { |
| $(this.get('element')).detach(); |
| App.router.get('backgroundOperationsController').set('levelInfo.name', 'OPS_LIST'); |
| } else { |
| this.hide(); |
| self.set('isPopup', null); |
| } |
| }, |
| |
| onPrimary: function () { |
| this.closeModelPopup(); |
| }, |
| |
| onClose: function () { |
| this.closeModelPopup(); |
| }, |
| |
| secondary: null, |
| |
| bodyClass: App.HostProgressPopupBodyView.extend({ |
| controller: self |
| }) |
| |
| })); |
| |
| return this.get('isPopup'); |
| } |
| }); |