Shows all the active incidents grouped by Service. For installation instructions check https://github.com/PedroFuentes/bitbar-plugins/blob/master/pagerDutyIncidents/README.md
#!/usr/bin/env /usr/local/bin/node
/*
<xbar.title>PagerDuty Incidents</xbar.title>
<xbar.version>v0.2.0</xbar.version>
<xbar.author>Pedro Pablo Fuentes Schuster</xbar.author>
<xbar.author.github>pedrofuentes</xbar.author.github>
<xbar.desc>Shows all the active incidents grouped by Service. For installation instructions check https://github.com/PedroFuentes/bitbar-plugins/blob/master/pagerDutyIncidents/README.md</xbar.desc>
<xbar.image>http://cdn.pedrofuent.es/images/github/PagerDutyIncidents_Screenshot.png</xbar.image>
<xbar.dependencies>node, npm/node-fetch, npm/time-ago, npm/bitbar, npm/home-config</xbar.dependencies>
<xbar.abouturl>https://github.com/PedroFuentes/bitbar-plugins/tree/master/pagerDutyIncidents</xbar.abouturl>
*/
/* MIT Licensed https://opensource.org/licenses/MIT */
/* jshint esversion: 6 */
'use strict';
const fetch = require('node-fetch');
const ta = require('time-ago')();
const bitbar = require('bitbar');
const cfg = require('home-config').load('.bitbarrc');
if (!cfg.pagerdutyincidents || !cfg.pagerdutyincidents['api.endpoint'] || !cfg.pagerdutyincidents['api.token']) {
const json = [];
json.push({
text: 'Config Needed',
dropdown: false,
},
bitbar.sep, {
text: 'Add to your .bitbarrc config file on your',
}, {
text: 'home directory the following information:',
},
bitbar.sep, {
text: '[pagerdutyincidents]',
}, {
text: 'api.endpoint=https://',
}, {
text: 'api.token={your-token}',
});
bitbar(json);
process.exit();
}
const config = {
api: {
endpoint: cfg.pagerdutyincidents['api.endpoint'],
token: cfg.pagerdutyincidents['api.token'],
query: cfg.pagerdutyincidents['api.query'] ? cfg.pagerdutyincidents['api.query'] : 'limit=100&statuses[]=triggered&statuses[]=acknowledged',
},
icon: {
active: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6REEwQjNEREYxNjBCMTFFNjgyODVBMzc1NTdCRDNBRUYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6REEwQjNERTAxNjBCMTFFNjgyODVBMzc1NTdCRDNBRUYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEQTBCM0RERDE2MEIxMUU2ODI4NUEzNzU1N0JEM0FFRiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEQTBCM0RERTE2MEIxMUU2ODI4NUEzNzU1N0JEM0FFRiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv4ywmgAAADTSURBVHja1NOtCgJBFIbhGX8QNYkGg6jFm7CZNXodglGL1RsQMQsmjUaTyWYzWAzGFfxji+L6LpyFYZmybBAHnrDLme8MZ3a1UspTMVZCxVw/Cdjgar7wIqpiFzynQulbrPBBGT1kMMUJfv0FyWCDGXBDF02UMIOLGkbo4I0XtC3Akc4LZDHGHg+0MZe6ugRZh5gw042lQzNTthP4m+/oI4+1dK5giSGeMoOCLUBLuiNFLQyQwxkHqZugYbvGowzPjXKt5gyK0jEd5avS//8zfQUYAGZtQSNj7zxTAAAAAElFTkSuQmCC',
inactive: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzI0MzNGNUIxNjBFMTFFNkEwRTE5QTI1QkJBMzA0MjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzI0MzNGNUMxNjBFMTFFNkEwRTE5QTI1QkJBMzA0MjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozMjQzM0Y1OTE2MEUxMUU2QTBFMTlBMjVCQkEzMDQyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozMjQzM0Y1QTE2MEUxMUU2QTBFMTlBMjVCQkEzMDQyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Poh/go0AAADaSURBVHja1NM9CsIwFMDxRjuIqJuj4AX0DJ5BRPAKdRAn3Z0Fxc0TiKK7Lp7F0cmKg9/Gf+BVAlahFAQDP5K+ti8vaaq01k6clnBitt8nUEqN4L0CZg+ioO2xCK5dK7MZV1CVyjYY4IYWCjLO4hS851rVddDDHAe0TYE4oouVPK/wCEtQwhl1StNU1GdclARTQp5U6tOlwzbx24H4eM+uwMyewpBZLvQ1jHFFk9iOPoMctmEJglnySGJmkuEusbKsvYHl22ekTWS9KspntStYw498sP7/Z3oKMAD3DYQymUW7vgAAAABJRU5ErkJggg==',
},
colors: {
critical: '#FF0000',
warning: '#999900',
regularText: '#808080',
},
};
// TODO: load all available pages
fetch(`${config.api.endpoint}/incidents?${config.api.query}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Token token=${config.api.token}`,
},
})
.then((res) => res.json())
.then((json) => {
// Group incidents by Service
const serviceIncidents = [];
json.incidents.forEach((incident) => {
if (!serviceIncidents[incident.service.id]) {
serviceIncidents[incident.service.id] = {
name: incident.service.summary,
html_url: incident.service.html_url,
incidents: [],
};
}
serviceIncidents[incident.service.id].incidents.push(incident);
});
return {
serviceIncidents,
total: json.incidents.length,
};
})
.then((obj) => {
const json = [];
const { serviceIncidents } = obj;
json.push({
text: `[${obj.total}]`,
dropdown: false,
templateImage: config.icon.inactive,
size: 8,
},
bitbar.sep);
if (Object.keys(serviceIncidents).length) {
Object.keys(serviceIncidents).forEach((prop) => {
const incidents = [];
serviceIncidents[prop].incidents.forEach((incident) => {
const assignedTo = [];
incident.assignments.forEach((user) => {
assignedTo.push({
text: `${user.assignee.summary}, ${ta.ago(new Date(Date.parse(user.at)))}`,
href: user.assignee.html_url,
color: config.colors.regularText,
}, {
text: user.assignee.html_url,
alternate: true,
});
});
incidents.push({
text: incident.title,
length: 50,
href: incident.html_url,
color: incident.status === 'triggered' ? config.colors.critical : config.colors.warning,
}, {
text: incident.title,
alternate: true,
}, {
text: 'Assigned To',
submenu: assignedTo,
}, {
text: `Created\t\t: ${ta.ago(new Date(Date.parse(incident.created_at)))}`,
color: config.colors.regularText,
}, {
text: `Created at\t: ${incident.created_at}`,
alternate: true,
color: config.colors.regularText,
}, {
text: `Status\t\t: ${incident.status}`,
color: config.colors.regularText,
}, {
text: `Urgency\t\t: ${incident.urgency}`,
color: config.colors.regularText,
}, {
text: `Escalations\t: ${incident.alert_counts.all}`,
color: config.colors.regularText,
});
});
json.push({
text: `${serviceIncidents[prop].name} (${serviceIncidents[prop].incidents.length})`,
href: serviceIncidents[prop].html_url,
submenu: incidents,
},
bitbar.sep);
});
} else {
json.push({
text: 'No Open Incidents',
});
}
bitbar(json);
});