blob: cc5230dedaa0ab9054ca8a6b339f21729bd468a7 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/**
* The header row of the summary table.
*
* In the "global" view, it shows the aggregation switch and all the zones. In
* the "zone" view, it shows all the instances for that zone.
*/
var hg = require('mercury');
var h = require('mercury').h;
var Consts = require('../../constants');
var AppStateMgr = require('../../appstate-manager');
var Util = require('../../util');
module.exports = {
render: render
};
/** The main render function. */
function render(state) {
var data = state.data.Zones;
var level = AppStateMgr.getAppState('level');
// First column is the aggregation switch.
var cols = [renderGlobalLevelAggSwitch(state)];
// Generate the rest of the columns.
var headers = [];
if (level === 'global') {
// In the "global" level, add all the zones.
headers = Consts.orderedZones.filter(function(zone) {
return data[zone];
});
} else if (level === 'zone') {
// In the "zone" level, add instances based on the type.
var zoneLevelZone = AppStateMgr.getAppState('zoneLevelZone');
var zoneLevelType = AppStateMgr.getAppState('zoneLevelType');
var instancePrefix =
(zoneLevelType === 'CloudService' ? 'vanadium-' : 'nginx-');
// Filter instances by instancePrefix (determined by zoneLevelType).
headers = Object.keys(data[zoneLevelZone].Instances)
.sort().filter(function(name) {
return name.startsWith(instancePrefix);
});
}
cols = cols.concat(renderHeaders(state, headers));
return h('div.zone-names-row', cols);
}
/** Renders the aggregtion type switch. */
function renderGlobalLevelAggSwitch(state) {
var aggType = AppStateMgr.getAppState('globalLevelAggType');
var level = AppStateMgr.getAppState('level');
if (level === 'global') {
// Only generate the switch (two links: average and max) in the "global"
// level to specify the aggregation method for all the cell data.
return h('div.view-type.zone-name-cell', [
h('div.average', {
className: aggType === 'Average' ? 'selected' : '',
'ev-click': hg.send(state.channels.changeGlobalLevelAggType, 'Average')
}, 'average'),
h('div.max', {
className: aggType === 'Max' ? 'selected' : '',
'ev-click': hg.send(state.channels.changeGlobalLevelAggType, 'Max')
}, 'max')
]);
} else {
// In the "zone" level, don't show the switch.
return h('div.view-type-dummy');
}
}
/**
* Renders the given headers.
* @param {hg.state} state
* @param {Array<string>} headers
*/
function renderHeaders(state, headers) {
var hoveredColumn = state.hoveredCellData.column;
return headers.map(function(header) {
var className = 'zone-name-cell';
if (header === hoveredColumn) {
className += '.highlight';
}
if (!checkMetricsHealthForHeader(state, header)) {
className += '.unhealthy';
}
return h('div.' + className, h('span', shortenHeaderLabel(header)));
});
}
/**
* Checks whether all the metrics for the given header are healthy.
* @param {hg.state} state
* @param {string} header
* @return {boolean}
*/
function checkMetricsHealthForHeader(state, header) {
var data = state.data.Zones;
var aggType = AppStateMgr.getAppState('globalLevelAggType');
var level = AppStateMgr.getAppState('level');
var isHealthy = true;
// In different levels, we check different health data for a given header.
// The health data is already calculated and recorded in the data object
// loaded from the backend server.
var i, curMetric;
if (level === 'global') {
var zone = header;
var aggData = data[zone][aggType];
for (i = 0; i < Consts.mainMetrics.length; i++) {
curMetric = Consts.mainMetrics[i];
if (!Util.isEmptyObj(aggData[curMetric.dataKey])) {
var metricAggData = aggData[curMetric.dataKey][curMetric.metricKey];
if (!metricAggData || !metricAggData.Healthy) {
isHealthy = false;
break;
}
}
}
} else if (level === 'zone') {
var instance = header;
var zoneLevelZone = AppStateMgr.getAppState('zoneLevelZone');
var zoneLevelType = AppStateMgr.getAppState('zoneLevelType');
var metrics = (zoneLevelType === 'CloudService' ?
Consts.cloudServiceMetrics : Consts.nginxMetrics);
var instanceData = data[zoneLevelZone].Instances[instance];
for (i = 0; i < metrics.length; i++) {
curMetric = metrics[i];
if (!Util.isEmptyObj(instanceData[curMetric.dataKey])) {
var metricData = instanceData[curMetric.dataKey][curMetric.metricKey];
if (!metricData || !metricData.Healthy) {
isHealthy = false;
break;
}
}
}
}
return isHealthy;
}
/**
* Shortens the header label by removing the common prefix.
* @param {string} header
* @return {string} The shortened header label.
*/
function shortenHeaderLabel(header) {
if (header.startsWith('vanadium')) {
return header.replace('vanadium-', '');
}
if (header.startsWith('nginx')) {
return header.replace('nginx-', '');
}
return header;
}