blob: 53f2953019d7c91504c887368cf286090b367818 [file] [log] [blame]
/**
* 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 sort = require('views/common/sort_view');
App.MainHostView = App.TableView.extend(App.TableServerViewMixin, {
templateName:require('templates/main/host'),
tableName: 'Hosts',
updaterBinding: 'App.router.updateController',
filterConditions: [],
/**
* Select/deselect all visible hosts flag
* @property {bool}
*/
selectAllHosts: false,
/**
* Contains all selected hosts on cluster
*/
selectedHosts: [],
/**
* Request error data
*/
requestError: null,
/**
* List of hosts in cluster
* @type {Array}
*/
contentBinding: 'controller.content',
filteredContent: [],
filteredContentObserver: function() {
Em.run.once(this, this.setFilteredContentOnce);
}.observes('content.@each'),
setFilteredContentOnce: function() {
this.set('filteredContent', this.get('content').filterProperty('isFiltered'));
},
onRequestErrorHandler: function() {
this.set('requestError', null);
this.set('filteringComplete', true);
this.propertyDidChange('pageContent');
}.observes('requestError'),
/**
* flag to toggle displaying selected hosts counter
*/
showSelectedFilter: Em.computed.bool('selectedHosts.length'),
/**
* return filtered number of all content number information displayed on the page footer bar
* @returns {String}
*/
filteredContentInfo: Em.computed.i18nFormat('hosts.filters.filteredHostsInfo', 'filteredCount', 'totalCount'),
/**
* request latest data filtered by new parameters
* called when trigger property(<code>refreshTriggers</code>) is changed
*/
refresh: function () {
App.loadTimer.start('Hosts Page');
this.set('filteringComplete', false);
var updaterMethodName = this.get('updater.tableUpdaterMap')[this.get('tableName')];
this.get('updater')[updaterMethodName](this.updaterSuccessCb.bind(this), this.updaterErrorCb.bind(this), true);
return true;
},
/**
* reset filters value by column to which filter belongs
* @param columns {Array}
*/
resetFilterByColumns: function (columns) {
var filterConditions = this.get('filterConditions');
columns.forEach(function (iColumn) {
var filterCondition = filterConditions.findProperty('iColumn', iColumn);
if (filterCondition) {
filterCondition.value = '';
this.saveFilterConditions(filterCondition.iColumn, filterCondition.value, filterCondition.type, filterCondition.skipFilter);
}
}, this);
},
/**
* Return pagination information displayed on the page
* @type {String}
*/
paginationInfo: Em.computed.i18nFormat('tableView.filters.paginationInfo', 'startIndex', 'endIndex', 'filteredCount'),
paginationLeftClass: function () {
if (this.get("startIndex") > 1 && this.get('filteringComplete')) {
return "paginate_previous";
}
return "paginate_disabled_previous";
}.property("startIndex", 'filteringComplete'),
previousPage: function () {
if (this.get('paginationLeftClass') === 'paginate_previous') {
this._super();
}
},
paginationRightClass: function () {
if ((this.get("endIndex")) < this.get("filteredCount") && this.get('filteringComplete')) {
return "paginate_next";
}
return "paginate_disabled_next";
}.property("endIndex", 'filteredCount', 'filteringComplete'),
nextPage: function () {
if (this.get('paginationRightClass') === 'paginate_next') {
this._super();
}
},
/**
* Select View with list of "rows-per-page" options
* @type {Ember.View}
*/
rowsPerPageSelectView: Em.Select.extend(App.PaginationSelectMixin, {
disabled: true,
disableView: function () {
Em.run.next(this, function(){
this.set('disabled', !this.get('parentView.dataView.filteringComplete'));
});
}.observes('parentView.dataView.filteringComplete'),
change: function () {
this.get('parentView.dataView').saveDisplayLength();
var self = this;
if (this.get('parentView.dataView.startIndex') !== 1 && this.get('parentView.dataView.startIndex') !== 0) {
Ember.run.next(function () {
self.set('parentView.dataView.startIndex', 1);
});
}
}
}),
saveStartIndex: function () {
this.set('controller.startIndex', this.get('startIndex'));
}.observes('startIndex'),
clearFiltersObs: function() {
var self = this;
Em.run.next(function() {
if (self.get('controller.clearFilters')) {
self.clearFilters();
}
});
},
/**
* Restore filter properties in view
*/
willInsertElement: function () {
if (!this.get('controller.showFilterConditionsFirstLoad')) {
// filters and start index should be cleared when we enter Hosts page
var didClearedFilters = this.clearFilterConditionsFromLocalStorage();
var didClearStartIndex = this.clearStartIndex();
this.set('controller.filterChangeHappened', didClearedFilters || didClearStartIndex);
}
if (!this.get('controller.saveSelection')) {
this.refresh();
}
this._super();
this.set('startIndex', this.get('controller.startIndex'));
this.set('displayLength', this.get('controller.paginationProps').findProperty('name', 'displayLength').value);
this.addObserver('pageContent.@each.selected', this, this.selectedHostsObserver);
},
/**
* stub for filter function in TableView
*/
filter: function () {
//Since filtering moved to server side, function is empty
},
didInsertElement: function() {
this.addObserver('controller.clearFilters', this, this.clearFiltersObs);
this.clearFiltersObs();
this.addObserver('selectAllHosts', this, this.toggleAllHosts);
this.addObserver('filteringComplete', this, this.overlayObserver);
this.addObserver('startIndex', this, 'updatePagination');
this.addObserver('displayLength', this, 'updatePagination');
this.addObserver('filteredCount', this, this.updatePaging);
// should show overlay even when filtering has begun before observer was added
this.overlayObserver();
this.combineSelectedFilter();
},
willDestroyElement: function () {
$('.tooltip').remove();
},
onInitialLoad: function () {
if (this.get('tableFilteringComplete')) {
if (this.get('controller.filterChangeHappened')) {
this.refresh();
} else {
// no refresh but still need to enable pagination controls
this.propertyDidChange('filteringComplete');
}
}
// reset filter change marker
this.set('controller.filterChangeHappened', false);
}.observes('tableFilteringComplete'),
/**
* Set <code>selected</code> property for each App.Host
*/
toggleAllHosts: function() {
this.get('pageContent').setEach('selected', this.get('selectAllHosts'));
},
/**
* Trigger updating <code>selectedHostsCount</code> only 1 time
*/
selectedHostsObserver: function() {
Ember.run.once(this, 'updateCheckedFlags');
},
/**
* Update <code>selectAllHosts</code> value
*/
updateCheckedFlags: function() {
this.removeObserver('selectAllHosts', this, this.toggleAllHosts);
if (this.get('pageContent').length) {
this.set('selectAllHosts', this.get('pageContent').everyProperty('selected', true));
}
else {
this.set('selectAllHosts', false);
}
this.combineSelectedFilter();
App.db.setSelectedHosts(this.get('selectedHosts'));
this.addObserver('selectAllHosts', this, this.toggleAllHosts);
},
/**
* combine selected hosts on page with selected hosts which are filtered out but added to cluster
*/
combineSelectedFilter: function () {
var previouslySelectedHosts = App.db.getSelectedHosts();
var selectedHosts = [];
var hostsOnPage = this.get('pageContent').mapProperty('hostName');
selectedHosts = this.get('pageContent').filterProperty('selected').mapProperty('hostName');
previouslySelectedHosts.forEach(function (hostName) {
if (!hostsOnPage.contains(hostName)) {
selectedHosts.push(hostName);
}
}, this);
this.set('selectedHosts', selectedHosts);
},
/**
* filter selected hosts
*/
filterSelected: function() {
//10 is an index of selected column
this.updateFilter(10, this.get('selectedHosts'), 'multiple');
},
/**
* Show spinner when filter/sorting request is in processing
* @method overlayObserver
*/
overlayObserver: function() {
var $tbody = this.$('tbody'),
$overlay = this.$('.table-overlay'),
$spinner = $($overlay).find('.spinner');
if (!this.get('filteringComplete')) {
if (!$tbody) return;
var tbodyPos = $tbody.position();
if (!tbodyPos) return;
$spinner.css('display', 'block');
$overlay.css({
top: tbodyPos.top + 1,
left: tbodyPos.left + 1,
width: $tbody.width() - 1,
height: $tbody.height() - 1
});
}
},
/**
* Clear selectedFilter
* Set <code>selected</code> to false for each host
*/
clearSelection: function() {
this.get('pageContent').setEach('selected', false);
this.set('selectAllHosts', false);
App.db.setSelectedHosts([]);
this.get('selectedHosts').clear();
this.filterSelected();
},
sortView: sort.serverWrapperView,
nameSort: sort.fieldView.extend({
column: 1,
name:'hostName',
displayName: Em.I18n.t('common.name')
}),
ipSort: sort.fieldView.extend({
column: 2,
name:'ip',
displayName: Em.I18n.t('common.ipAddress'),
type: 'ip'
}),
rackSort: sort.fieldView.extend({
column: 12,
name:'rack',
displayName: Em.I18n.t('common.rack'),
type: 'rack'
}),
cpuSort: sort.fieldView.extend({
column: 3,
name:'cpu',
displayName: Em.I18n.t('common.cores'),
type: 'number'
}),
memorySort: sort.fieldView.extend({
column: 4,
name:'memoryFormatted',
displayName: Em.I18n.t('common.ram'),
type: 'number'
}),
diskUsageSort: sort.fieldView.extend({
name:'diskUsage',
displayName: Em.I18n.t('common.diskUsage')
}),
loadAvgSort: sort.fieldView.extend({
column: 5,
name:'loadAvg',
displayName: Em.I18n.t('common.loadAvg'),
type: 'number'
}),
HostView: Em.View.extend({
content: null,
tagName: 'tr',
classNameBindings: ['content.selected:active'],
didInsertElement: function(){
App.tooltip(this.$("[rel='HealthTooltip'], [rel='UsageTooltip'], [rel='ComponentsTooltip']"));
},
willDestroyElement: function() {
this.$("[rel='HealthTooltip'], [rel='UsageTooltip'], [rel='ComponentsTooltip']").remove();
},
displayComponents: function () {
if (this.get('hasNoComponents')) {
return;
}
var header = Em.I18n.t('common.components'),
hostName = this.get('content.hostName'),
items = this.get('content.hostComponents').getEach('displayName');
App.showHostsTableListPopup(header, hostName, items);
},
displayVersions: function () {
if (this.get('hasSingleVersion')) {
return;
}
var header = Em.I18n.t('common.versions'),
hostName = this.get('content.hostName'),
items = this.get('content.stackVersions').filterProperty('isVisible').map(function (stackVersion) {
return {
name: stackVersion.get('displayName'),
status: App.format.role(stackVersion.get('status'), false)
};
});
App.showHostsTableListPopup(header, hostName, items);
},
/**
* Tooltip message for "Restart Required" icon
* @returns {String}
*/
restartRequiredComponentsMessage: function() {
var restartRequiredComponents = this.get('content.componentsWithStaleConfigs');
var count = this.get('content.componentsWithStaleConfigsCount');
if (count <= 5) {
var word = (count == 1) ? Em.I18n.t('common.component') : Em.I18n.t('common.components');
return Em.I18n.t('hosts.table.restartComponents.withNames').format(restartRequiredComponents.getEach('displayName').join(', ')) + ' ' + word.toLowerCase();
}
return Em.I18n.t('hosts.table.restartComponents.withoutNames').format(count);
}.property('content.componentsWithStaleConfigs'),
/**
* Tooltip message for "Maintenance" icon
* @returns {String}
*/
componentsInPassiveStateMessage: function() {
var componentsInPassiveState = this.get('content.componentsInPassiveState');
var count = this.get('content.componentsInPassiveStateCount');
if (count <= 5) {
return Em.I18n.t('hosts.table.componentsInPassiveState.withNames').format(componentsInPassiveState.getEach('displayName').join(', '));
}
return Em.I18n.t('hosts.table.componentsInPassiveState.withoutNames').format(count);
}.property('content.componentsInPassiveState'),
/**
* true if host has only one repoversion
* in this case expander in version column is hidden
* @returns {Boolean}
*/
hasSingleVersion: function() {
return this.get('content.stackVersions').filterProperty('isVisible', true).length < 2;
}.property('content.stackVersions.length'),
/**
* true if host has no components
* @returns {Boolean}
*/
hasNoComponents: Em.computed.empty('content.hostComponents'),
/**
/**
* this version is always shown others hidden unless expander is open
* host may have no stack versions
* @returns {String}
*/
currentVersion: function() {
var currentRepoVersion = this.get('content.stackVersions').findProperty('isCurrent') || this.get('content.stackVersions').objectAt(0);
return currentRepoVersion ? currentRepoVersion.get('displayName') : "";
}.property('content.stackVersions'),
/**
* CSS value for disk usage bar
* @returns {String}
*/
usageStyle:function () {
return "width:" + this.get('content.diskUsage') + "%";
}.property('content.diskUsage')
}),
/**
* associations between host property and column index
* @type {Array}
*/
colPropAssoc: Em.computed.alias('controller.colPropAssoc'),
/**
* Run <code>clearFilter</code> in the each child filterView
*/
clearFilters: function() {
// clean filters stored in-memory and local storage
this.set('filterConditions', []);
this.clearFilterConditionsFromLocalStorage();
// force refresh
this.refresh();
}
});