(function() {
var fitopts = {min: 6, max: 1000};
var Grid = function(json) {
view.View.call(this, json);
this.query = json.query;
this.title = json.title;
this.max = json.max || "all";
this.by = json.by || "host";
this.clickFocusable = true;
// Initial display
this.el.addClass('grid');
this.el.append(
'
' +
''
);
this.box = this.el.find('.box');
this.el.find('h2').text(this.title);
// State
this.columns = [];
this.rows = [];
this.hosts = [];
this.services = [];
this.events = {};
if (this.max === "service" || this.max === "host") {
this.currentMax = {};
}
// Subscribe
if (this.query) {
var me = this;
this.sub = subs.subscribe(this.query, function(e) {
me.update.call(me, e);
});
}
}
view.inherit(view.View, Grid);
view.Grid = Grid;
view.types.Grid = Grid;
Grid.prototype.json = function() {
return $.extend(view.View.prototype.json.call(this), {
type: 'Grid',
title: this.title,
query: this.query,
max: this.max,
by: this.by
});
}
var editTemplate = _.template(
"" +
"
" +
"
" +
"
" +
"" +
"
" +
"'host' or 'service'
" +
"" +
"
" +
"'all', 'host', 'service', or any number."
)
Grid.prototype.editForm = function() {
return editTemplate(this);
}
// Returns all events, flat.
Grid.prototype.allEvents = function() {
var events = [];
for (row in this.events) {
for (column in this.events[row]) {
events.push(this.events[row][column]);
}
}
}
// What is the maximum for this event?
Grid.prototype.eventMax = function(event) {
if (this.max === "host") {
return this.currentMax[event.host] || -1/0;
} else if (this.max === "service") {
return this.currentMax[event.service] || -1/0;
} else {
return this.currentMax || -1/0;
}
}
// Update a single jq element with information about an event.
Grid.prototype.renderElement = function(element, event) {
if (event === undefined) {
return;
}
// State
element.attr('class', "state box " + event.state);
// Metric
element.find('.metric').text(format.float(event.metric));
// Description
element.attr('title', event.state + ' at ' + event.time + "\n\n" +
event.description);
// Bar chart
if (event.metric == 0) {
// Zero
element.find('.bar').css('width', 0);
} else if (0 < event.metric) {
// Positive
element.find('.bar').css('width',
(event.metric / this.eventMax(event) * 100) + "%");
} else {
// Nil or negative
element.find('.bar').css('width', 0);
}
}
// Render a single event if there's been no change to table structure.
Grid.prototype.partialRender = function(event) {
var table = this.el.find('table');
if (this.by === "host") {
var rowIndex = this.rows.indexOf(event.host);
var columnIndex = this.columns.indexOf(event.service);
} else {
var rowIndex = this.rows.indexOf(event.service);
var columnIndex = this.columns.indexOf(event.host)
}
var row = this.el.find('tbody tr')[rowIndex];
var td = $($(row).find('td')[columnIndex]);
this.renderElement(td, event);
}
// Rerender the table
Grid.prototype.render = util.slur(200, function() {
var table = this.el.find('table');
table.empty();
// Header
table.append(" |
");
var row = table.find("thead tr");
this.columns.forEach(function(name) {
var element = $('');
element.text(name);
row.append(element);
});
this.rows.forEach(function(name) {
row = $(" | | ");
table.append(row);
row.find('th').text(name);
this.columns.forEach(function(subName) {
var event = this.events[name][subName];
var element = $(' | ');
this.renderElement(element, event);
row.append(element);
}, this);
}, this);
});
// Update cached maxima with a new event. Returns true if maxima changed.
Grid.prototype.updateMax = function(event) {
if (event !== undefined &&
(event.metric === undefined ||
event.metric <= (this.eventMax(event) || -1/0))) {
// We haven't bumped our max; no change.
return false;
}
var e;
if (this.max === "all") {
this.currentMax = -1/0;
for (name in this.events) {
for (subName in this.events[name]) {
e = this.events[name][subName];
this.currentMax = Math.max(e.metric, this.currentMax || -1/0);
}
}
} else if (this.by == "host") {
if (this.max == "host") {
this.currentMax = {};
for (host in this.events) {
for (service in this.events[host]) {
e = this.events[host][service];
this.currentMax[e.host] =
Math.max(e.metric, this.currentMax[e.host] || -1/0)
}
}
} else if (this.max === "service") {
this.currentMax = {};
for (host in this.events) {
for (service in this.events[host]) {
e = this.events[host][service];
this.currentMax[e.service] =
Math.max(e.metric, this.currentMax[e.service] || -1/0);
}
}
}
} else if (this.by === "service") {
if (this.max == "host") {
this.currentMax = {};
for (service in this.events) {
for (host in this.events[service]) {
e = this.events[service][host];
this.currentMax[e.host] =
Math.max(e.metric, this.currentMax[e.host] || -1/0)
}
}
} else if (this.max === "service") {
this.currentMax = {};
for (service in this.events) {
for (host in this.events[service]) {
e = this.events[service][host];
this.currentMax[e.service] =
Math.max(e.metric, this.currentMax[e.service] || -1/0);
}
}
}
} else {
this.currentMax = this.max;
return false;
}
return true;
}
// Stores an event in the internal state tables. Returns true if we
// haven't seen this host/service before.
Grid.prototype.saveEvent = function(e) {
if (this.by === "host") {
// Host list
if (this.rows.indexOf(e.host) === -1) {
this.rows.push(e.host);
this.rows = _.uniq(this.rows.sort(), true);
}
// Services list
if (this.columns.indexOf(e.service) === -1) {
this.columns.push(e.service);
this.columns = _.uniq(this.columns.sort(), true);
}
// Events map
if (this.events[e.host] === undefined) {
// New host
this.events[e.host] = {};
}
var newEvent = (this.events[e.host][e.service] === undefined);
// Store event
this.events[e.host][e.service] = e;
return newEvent;
} else if (this.by === "service") {
// Services list
if (this.rows.indexOf(e.service) === -1) {
this.rows.push(e.service);
this.rows = _.uniq(this.rows.sort(), true);
}
// Host list
if (this.columns.indexOf(e.host) === -1) {
this.columns.push(e.host);
this.columns = _.uniq(this.columns.sort(), true);
}
// Events map
if (this.events[e.service] === undefined) {
// New host
this.events[e.service] = {};
}
var newEvent = (this.events[e.service][e.host] === undefined);
// Store event
this.events[e.service][e.host] = e;
return newEvent;
}
}
// Add an event.
Grid.prototype.add = function(e) {
var newEvent = this.saveEvent(e);
var newMax = this.updateMax(e);
if (newEvent || newMax) {
this.render();
} else {
this.partialRender(e);
}
}
// Remove an event.
Grid.prototype.remove = function(e) {
delete this.events[e.host][e.service];
if (_.isEmpty(this.events[e.host])) {
delete this.events[e.host];
};
// Recompute hosts
this.hosts = _.keys(this.events).sort();
// Recompute services
var services = {};
for (var host in this.events) {
for (var service in this.events[host]) {
services[this.events[host][service].service] = true;
}
}
this.services = _.keys(services).sort();
this.updateMax();
this.render();
}
// Accept an event.
Grid.prototype.update = function(e) {
if (e.state === "expired") {
this.remove(e);
} else {
this.add(e);
}
}
Grid.prototype.reflow = function() {
// this.el.find('table').height(
// this.height() -
// this.el.find('h2').height()
// );
}
Grid.prototype.delete = function() {
if (this.sub != undefined) {
subs.unsubscribe(this.sub);
}
this.update = function() {};
view.View.prototype.delete.call(this);
}
})();
---|