Skip to content

Instantly share code, notes, and snippets.

@freekrai
Last active March 9, 2017 07:31
Show Gist options
  • Save freekrai/4a3bd796a374fc6fd42f7359570372dd to your computer and use it in GitHub Desktop.
Save freekrai/4a3bd796a374fc6fd42f7359570372dd to your computer and use it in GitHub Desktop.
status page
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Service status">
<meta name="robots" content="index, follow">
<title>Status</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="style.css?v=20170223">
</head>
<body>
<div class="container">
<header>
<h1>Status Page</h1>
</header>
<div class="panel" id="panel">
<div class="panel-heading">
<h3 class="panel-title" id="paneltitle"></h3>
</div>
</div>
<h4 class="page-header">Systems Status</h4>
<div class="list-group" id="services"></div>
<h4 class="page-header">Incidents</h4>
<div class="timeline-centered" id="incidents"></div>
<script src="//code.jquery.com/jquery.min.js"></script>
<script src="script.js?v=20170223"></script>
</body>
</html>
$(document).ready(function() {
var config = {
uptimerobot: {
api_keys: [
"YOUR-UPTIME-ROBOT-API-KEY-1",
"YOUR-UPTIME-ROBOT-API-KEY-2"
],
logs: 1
},
github: {
org: 'YOUR-GITHUB-USERNAME',
repo: 'YOUR-GITHUB-REPO'
}
};
var status_text = {
'operational': 'operational',
'investigating': 'investigating',
'major outage': 'outage',
'degraded performance': 'degraded',
};
var monitors = config.uptimerobot.api_keys;
for( var i in monitors ){
var api_key = monitors[i];
$.post('https://api.uptimerobot.com/v2/getMonitors', {
"api_key": api_key,
"format": "json",
"logs": config.uptimerobot.logs,
}, function(response) {
status( response );
}, 'json');
}
function status(data) {
data.monitors = data.monitors.map(function(check) {
check.class = check.status === 2 ? 'label-success' : 'label-danger';
check.text = check.status === 2 ? 'operational' : 'major outage';
if( check.status !== 2 && !check.lasterrortime ){
check.lasterrortime = Date.now();
}
if (check.status === 2 && Date.now() - (check.lasterrortime * 1000) <= 86400000) {
check.class = 'label-warning';
check.text = 'degraded performance';
}
return check;
});
var status = data.monitors.reduce(function(status, check) {
return check.status !== 2 ? 'danger' : 'operational';
}, 'operational');
if (!$('#panel').data('incident')) {
$('#panel').attr('class', (status === 'operational' ? 'panel-success' : 'panel-warning') );
$('#paneltitle').html(status === 'operational' ? 'All systems are operational.' : 'One or more systems inoperative');
}
data.monitors.forEach(function(item) {
var name = item.friendly_name;
var clas = item.class;
var text = item.text;
$('#services').append('<div class="list-group-item">'+
'<span class="badge '+ clas + '">' + text + '</span>' +
'<h4 class="list-group-item-heading">' + name + '</h4>' +
'</div>');
});
};
$.getJSON( 'https://api.github.com/repos/' + config.github.org + '/' + config.github.repo + '/issues?state=all' ).done(message);
function message(issues) {
issues.forEach(function(issue) {
var status = issue.labels.reduce(function(status, label) {
if (/^status:/.test(label.name)) {
return label.name.replace('status:', '');
} else {
return status;
}
}, 'operational');
var systems = issue.labels.filter(function(label) {
return /^system:/.test(label.name);
}).map(function(label) {
return label.name.replace('system:', '')
});
if (issue.state === 'open') {
$('#panel').data('incident', 'true');
$('#panel').attr('class', (status === 'operational' ? 'panel-success' : 'panel-warn') );
$('#paneltitle').html('<a href="#incidents">' + issue.title + '</a>');
}
var html = '<article class="timeline-entry">\n';
html += '<div class="timeline-entry-inner">\n';
if (issue.state === 'closed') {
html += '<div class="timeline-icon bg-success"><i class="entypo-feather"></i></div>';
} else {
html += '<div class="timeline-icon bg-secondary"><i class="entypo-feather"></i></div>';
}
html += '<div class="timeline-label">\n';
html += '<span class="date">' + datetime(issue.created_at) + '</span>\n';
if (issue.state === 'closed') {
html += '<span class="badge label-success pull-right">closed</span>';
} else {
html += '<span class="badge ' + (status === 'operational' ? 'label-success' : 'label-warn') + ' pull-right">open</span>\n';
}
for (var i = 0; i < systems.length; i++) {
html += '<span class="badge system pull-right">' + systems[i] + '</span>';
}
html += '<h2>' + issue.title + '</h2>\n';
html += '<hr>\n';
html += '<p>' + issue.body + '</p>\n';
if (issue.state === 'closed') {
html += '<p><em>Updated ' + datetime(issue.closed_at) + '<br/>';
html += 'The system is back in normal operation.</p>';
}
html += '</div>';
html += '</div>';
html += '</article>';
$('#incidents').append(html);
});
function datetime(string) {
var datetime = string.split('T');
var date = datetime[0];
var time = datetime[1].replace('Z', '');
return date + ' ' + time;
};
};
});
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,700italic,400,300,700");
.timeline-centered .timeline-entry .timeline-entry-inner:after,
.timeline-centered .timeline-entry:after,
.timeline-centered:after {
clear: both
}
img {
vertical-align: middle
}
.img-responsive {
display: block;
height: auto;
max-width: 100%
}
.img-rounded {
border-radius: 3px
}
.img-thumbnail {
background-color: #fff;
border: 1px solid #ededf0;
border-radius: 3px;
display: inline-block;
height: auto;
line-height: 1.428571429;
max-width: 100%;
moz-transition: all .2s ease-in-out;
o-transition: all .2s ease-in-out;
padding: 2px;
transition: all .2s ease-in-out;
webkit-transition: all .2s ease-in-out
}
.img-circle {
border-radius: 50%
}
.timeline-centered {
position: relative;
margin-bottom: 30px
}
.timeline-centered:after,
.timeline-centered:before {
content: " ";
display: table
}
.timeline-centered:before {
content: '';
position: absolute;
display: block;
width: 4px;
background: #f5f5f6;
top: 20px;
bottom: 20px;
margin-left: 30px
}
.timeline-centered .timeline-entry .timeline-entry-inner:after,
.timeline-centered .timeline-entry .timeline-entry-inner:before,
.timeline-centered .timeline-entry:after,
.timeline-centered .timeline-entry:before {
content: " ";
display: table
}
.timeline-centered .timeline-entry {
position: relative;
margin-top: 5px;
margin-left: 30px;
margin-bottom: 10px;
clear: both
}
.timeline-centered .timeline-entry.begin {
margin-bottom: 0
}
.timeline-centered .timeline-entry.left-aligned {
float: left
}
.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner {
margin-left: 0;
margin-right: -18px
}
.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-time {
left: auto;
right: -100px;
text-align: left
}
.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-icon {
float: right
}
.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-label {
margin-left: 0;
margin-right: 70px
}
.timeline-centered .timeline-entry.left-aligned .timeline-entry-inner .timeline-label:after {
left: auto;
right: 0;
margin-left: 0;
margin-right: -9px;
-moz-transform: rotate(180deg);
-o-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg)
}
.timeline-centered .timeline-entry .timeline-entry-inner {
position: relative;
margin-left: -20px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-time {
position: absolute;
left: -100px;
text-align: right;
padding: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-time>span {
display: block
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-time>span:first-child {
font-size: 15px;
font-weight: 700
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-time>span:last-child {
font-size: 12px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon {
background: #fff;
color: #737881;
display: block;
width: 40px;
height: 40px;
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
text-align: center;
-moz-box-shadow: 0 0 0 5px #f5f5f6;
-webkit-box-shadow: 0 0 0 5px #f5f5f6;
box-shadow: 0 0 0 5px #f5f5f6;
line-height: 40px;
font-size: 15px;
float: left
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-primary {
background-color: #303641;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-secondary {
background-color: #ee4749;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-success {
background-color: #00a651;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-info {
background-color: #21a9e1;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-warning {
background-color: #fad839;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-icon.bg-danger {
background-color: #cc2424;
color: #fff
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label {
position: relative;
background: #f5f5f6;
padding: 1em;
margin-left: 60px;
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label:after {
content: '';
display: block;
position: absolute;
width: 0;
height: 0;
border-style: solid;
border-width: 9px 9px 9px 0;
border-color: transparent #f5f5f6 transparent transparent;
left: 0;
top: 10px;
margin-left: -9px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label h2,
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label p {
color: #737881;
font-family: "Noto Sans", sans-serif;
font-size: 12px;
margin: 0;
line-height: 1.428571429
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label p+p {
margin-top: 15px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label h2 {
font-size: 16px;
margin-bottom: 10px
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label h2 a {
color: #303641
}
.timeline-centered .timeline-entry .timeline-entry-inner .timeline-label h2 span {
-webkit-opacity: .6;
-moz-opacity: .6;
opacity: .6;
-ms-filter: alpha(opacity=60);
filter: alpha(opacity=60)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment