Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Refactor timeline to look nice, be awesome #80

Closed
wants to merge 3 commits into
from
View
@@ -222,22 +222,16 @@ exports.create_basic_auth = function(username, password){
* @return {fn} middleware function
*/
exports.create_middleware = function(name, middleware){
- return function(req, res, next){
- // Do they have the api defined in the devops ball?
- if (!req.devops.related_apis || !req.devops.related_apis[name]) {
- req.devops[name] = null;
+ return function(req, res, next) {
+ var payload = {error: null, data: null};
+ req.devops[name] = payload;
+ try{
+ middleware(req, res, next, payload, req.devops.related_apis[name]);
+ } catch (e){
+ payload.error = e;
+ // TODO: this may not be callable if the error was with express
next();
- return;
}
- var payload = {error: null, data: null};
- req.devops[name] = payload;
- try{
- middleware(req, res, next, payload, req.devops.related_apis[name]);
- }catch (e){
- payload.error = e;
- // TODO: this may not be callable if the error was with express
- next();
- }
};
};
@@ -20,4 +20,16 @@ There are two kinds of middlewares:
populate data.
These middlewares are typically created via Utils.create_middleware which passes in two extra params: payload and api_config.
api_config maps to req.devops[middleware_name] while payload contains the data and error objects. Middlewares
- update the payload instead of setting the data and error fields on the devops object directly.
+ update the payload instead of setting the data and error fields on the devops object directly.
+
+Middlewares should set their payload to null when they discover they have no relevant credentials in the req.devops or api_config.
+
+```
+ // blank credentials test.
+ if (api_config === undefined ) {
+ payload = null ;
+ next();
+ return;
+ }
+```
+
@@ -29,6 +29,13 @@ request.prototype = {
module.exports = utils.create_middleware('dreadnot', function dreadnot(req, res, next, payload, api_config) {
+ // blank credentials test.
+ if (api_config === undefined ) {
+ payload = null ;
+ next();
+ return;
+ }
+
var requests = [];
_.each(api_config.stacks, function(a_stack){
_.each(_.keys(a_stack), function(stack_name){
@@ -21,6 +21,7 @@ module.exports = {
load_devops: require('./load_devops'),
navbar: require('./navbar'),
// independent devops middleware:
+ timeline: require('./timeline'),
pager_duty: require('./pager_duty'),
version_one: require('./version_one'),
github: require('./github'),
@@ -8,8 +8,13 @@ var _ = require('underscore');
* on_end_cb a callback that gets called with the XHR response data
*/
-module.exports = utils.create_middleware('pager_duty', function(req, res, next, payload, api_config) {
-
+module.exports = utils.create_middleware('pager_duty', function pager_duty(req, res, next, payload, api_config) {
+ // blank credentials test.
+ if (api_config === undefined ) {
+ payload = null ;
+ next();
+ return;
+ }
// PagerDuty requires the date range for all requests.
var now, until, options;
@@ -0,0 +1,61 @@
+var utils = require('../../utils');
+var _ = require('underscore');
+
+module.exports = utils.create_middleware('timeline', function timeline (req, res, next, payload) {
+
+ // blank credentials test.
+ if (req.devops.events === undefined ) {
+ payload = null;
+ next();
+ return;
+ }
+ var events = req.devops.events;
+ var max = 0;
+
+ var now = (new Date()).getTime();
+ var future_events = [];
+ var amt;
+
+ // define the position of the events
+ try {
+
+ for (var i=0; i<events.length; i++){
+ var event = events[i];
+ if (_.isNull(event.timestamp)){
+ continue;
+ }
+
+ // accept both ISO and unix timestamp formats
+ if (typeof (event.timestamp) === 'number') {
+ event.timestamp = new Date(event.timestamp * 1000);
+ } else {
+ event.timestamp = new Date(event.timestamp);
+ }
+
+ // get max
+ if (event.timestamp > max){
+ max = event.timestamp;
+ }
+ // make valid events list
+ if (event.timestamp > now){
+ future_events.push(event);
+ }
+ }
+ if (future_events.length > 1) {
+ future_events.sort(function(x,y) {
+ return y.timestamp < x.timestamp;
+ });
+ }
+ _.each(future_events, function(event){
+ event.days_remaining = Math.floor((event.timestamp - now) / (1000*60*60*24));
+ // figure out the amount and offset from the right 100px and from the left 25px
+ amt = ((event.timestamp - now) / (max - now + 1)) * 0.8;
+ event.position = amt * 100;
+ });
+ } catch(e) {
+ payload.error = e;
+ return next();
+ }
+ payload.data = {"events": future_events};
+ next();
+});
@@ -35,7 +35,15 @@ var selection = ["Custom_Severity.Name",
"Scope",
"Priority"];
-module.exports = utils.create_middleware('version_one', function(req, res, next, payload, api_config) {
+module.exports = utils.create_middleware('version_one', function version_one (req, res, next, payload, api_config) {
+
+ // blank credentials test.
+ if (api_config === undefined ) {
+ payload = null ;
+ next();
+ return;
+ }
+
var options = {
port: api_config.port,
host: api_config.host,
@@ -52,8 +60,8 @@ module.exports = utils.create_middleware('version_one', function(req, res, next,
'Authorization': 'Basic ' + new Buffer(api_config.auth).toString('base64')
}
};
-
- utils.request_maker(options,
+
+utils.request_maker(options,
function(error, data){
var byAge = {};
var now = new Date();
View
@@ -45,47 +45,15 @@ module.exports.install = function(app, secure_app, api_cache, devops_directory){
}, function(cb) {
middleware.new_relic(req, res, cb);
}, function(cb){
+ middleware.timeline(req, res, cb);
+ }, function(cb){
middleware.dreadnot(req, res, cb);
}
],
function(err) {
if (err) {
req.devops.errors.push(err);
}
-
- var events = req.devops.events;
- var max = 0;
-
- var now = (new Date()).getTime();
- var future_events = [];
- for (var i=0; i<events.length; i++){
- var event = events[i];
- if (_.isNull(event.timestamp)){
- continue;
- }
- // convert to seconds
- event.timestamp *= 1000;
- // get max
- if (event.timestamp > max){
- max = event.timestamp;
- }
- // make valid events list
- if (event.timestamp > now){
- future_events.push(event);
- }
- }
- if (future_events.length > 1) {
- future_events.sort(function(x,y) {
- return y.timestamp < x.timestamp;
- });
- }
- _.each(future_events, function(event){
- event.days_remaining = Math.floor((event.timestamp - now) / (1000*60*60*24));
- // figure out the amount and offset from the right 100px and from the left 25px
- var amt = ((event.timestamp - now) / (max - now + 1)) * 0.8;
- event.position = amt * 100;
- });
- req.devops.events = future_events;
res.render('index.jade', req.devops);
}
);
@@ -1,24 +0,0 @@
-.pager_duty
- h1 PagerDuty
- if pager_duty.error
- p #{pager_duty.error}
- else if pager_duty.data.error
- p API returned the following error:
- p.alert #{pager_duty.data.error.code}: #{pager_duty.data.error.message}
- else
- h4 Currently On Call:
- p
- ul
- li
- strong #{pager_duty.data.entries[0].user.name} <br>
- | from: #{pager_duty.data.entries[0].start}<br>
- | to: #{pager_duty.data.entries[0].end}
- p
- if pager_duty.data.entries[1]
- h4 Next On Call:
- p
- ul
- li
- strong #{pager_duty.data.entries[1].user.name} <br>
- | from: #{pager_duty.data.entries[1].start}<br>
- | to: #{pager_duty.data.entries[1].end}
@@ -0,0 +1,20 @@
+block append scripts
+
+
+if timeline.error
+ p.alert!=trace(timeline.error)
+else
+ for event in timeline.data.events
+ div.timeline-tooltip(style="left: #{event.position}%")
+ #{event.days_remaining}
+ div.alert.hide
+ b=event.name
+ br
+ #{event.description}
+ ul.related_links
+ if event.related_links
+ for link in event.related_links
+ li
+ a(href="#{link}") #{link}
+ span.date-info
+ #{event.days_remaining} days left - !{(new Date(event.timestamp)).toDateString()}
@@ -1,16 +0,0 @@
-block append scripts
-
-for event in events
- div.timeline-tooltip(style="left: #{event.position}%")
- #{event.days_remaining}
- div.alert.hide
- b=event.name
- br
- #{event.description}
- ul.related_links
- if event.related_links
- for link in event.related_links
- li
- a(href="#{link}") #{link}
- span.date-info
- #{event.days_remaining} days left - !{(new Date(event.timestamp)).toDateString()}
View
@@ -7,8 +7,9 @@ block append scripts
script(src='/static/js/contacts.js')
block content
- #timeline
- include includes/timeline_event
+ if timeline.error || timeline.data
+ #timeline
+ include includes/timeline
if errors.length
#errors.alert.alert-error
@@ -45,15 +46,15 @@ block content
#environments-block.ablock
include includes/environments
- if version_one
+ if version_one.error || version_one.data
#versionone-block.ablock.middleware-block
include includes/version_one
- if new_relic
+ if new_relic.error || new_relic.data
#newrelic-block.ablock.middleware-block
include includes/new_relic
- if dreadnot
+ if dreadnot.error || dreadnot.data
#dreadnot-block.ablock.middleware-block
include includes/dreadnot
View
@@ -16,8 +16,30 @@
.on-call { color: red; }
-#timeline {margin: 0 50px;}
+#timeline {margin: 0px 0px 30px 0px;}
#timeline-tooltip .name { font-weight: bold; }
#timeline-tooltip .date-info { font-size: .8em; display: block; text-align: right; }
-#timeline > div { position: absolute; cursor: pointer;}
+
+
+.timeline-tooltip {
+ position: absolute;
+ cursor: pointer;
+ border-radius: 999px;
+ behavior: url(PIE.htc);
+
+ width: 12px;
+ height: 12px;
+ padding: 10px;
+
+ background: #fff;
+ border: 2px solid #666;
+ color: #666;
+ text-align: center;
+
+ font: 12px Arial, sans-serif
+}
+
.contact-team li { padding: 2px 0px; }
+.alert {
+ width: 250px;
+}
Oops, something went wrong.