riemann-dash 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  var keys = (function() {
2
2
  var active = true;
3
-
3
+
4
4
  var bindings = {};
5
5
 
6
6
  // Disable bindings.
@@ -39,10 +39,22 @@ var strings = (function() {
39
39
  return match[1];
40
40
  }
41
41
  return '';
42
- }
42
+ }
43
+
44
+ // Shortens a list of strings by removing common prefixes.
45
+ var shorten = function(prefixFn, strings) {
46
+ var prefix = prefixFn(strings);
47
+ return _.map(strings, function(s) {
48
+ if (s && s.length !== prefix.length) {
49
+ return s.substring(prefix.length);
50
+ }
51
+ return s;
52
+ });
53
+ };
43
54
 
44
55
  return {
45
56
  commonPrefix: commonPrefix,
46
- longestCommonPrefix: longestCommonPrefix
57
+ longestCommonPrefix: longestCommonPrefix,
58
+ shorten: shorten
47
59
  }
48
60
  })();
@@ -49,20 +49,22 @@ var subs = (function() {
49
49
  return sub.open();
50
50
  }
51
51
 
52
- // Emit an expired event if oldest item from prioqueue is in the past.
52
+ // Emit expired events from the prioqueue.
53
53
  var expire = function(sub, now) {
54
54
  prioqueue = subs[sub.id].prioqueue;
55
- if (prioqueue) {
56
- bottom = prioqueue.bottomPriority();
57
- if (bottom) {
58
- expiry = new Date(bottom);
59
- if (expiry < now) {
60
- expired = prioqueue.shift();
61
- expired.time = expiry;
62
- expired.state = 'expired';
63
- sub.f(expired);
64
- }
55
+ if (! prioqueue) {
56
+ return;
57
+ }
58
+
59
+ while (bottom = prioqueue.bottomPriority()) {
60
+ expiry = new Date(bottom);
61
+ if (now < expiry) {
62
+ return;
65
63
  }
64
+ expired = prioqueue.shift();
65
+ expired.time = expiry;
66
+ expired.state = 'expired';
67
+ sub.f(expired);
66
68
  }
67
69
  }
68
70
 
@@ -11,13 +11,51 @@ var util = (function() {
11
11
  // A string key uniquely identifying an event by host and service.
12
12
  eventKey: function(e) {
13
13
  return nullableKey(e.host) + "\ufffe" + nullableKey(e.service);
14
- },
15
-
14
+ },
15
+
16
+ // Takes a string and returns a function that extracts a value from an
17
+ // event.
18
+ extract_fn: function(str) {
19
+ // When null/undefined, stay null/undefined.
20
+ if (! str) {
21
+ return str;
22
+ }
23
+
24
+ // Probably the worst hack ever. I'm not documenting this because it's so
25
+ // evil--though tremendously useful.
26
+ if (str.match(/^fn /)) {
27
+ // Grab the rest of the string, turn it into an anonymous fn taking a
28
+ // single arg `e`.
29
+ return Function.apply(null, ['e', str.substring(3)]);
30
+ }
31
+
32
+ // Property access
33
+ return function(e) {
34
+ return e[str];
35
+ };
36
+ },
37
+
38
+ // Takes a string and returns either:
39
+ // - a function which extracts a maximum value from an event.
40
+ // - a number to be used as the constant maximum.
41
+ max_fn: function(str) {
42
+ if ((!str) || str === "all") {
43
+ // Always the same value: global maxima
44
+ return function(e) { return "all"; };
45
+ }
46
+ if (isNaN(parseFloat(str))) {
47
+ // Not a number. Extract a field.
48
+ return function(e) { return e[str]; };
49
+ }
50
+ // Return a constant number.
51
+ return parseFloat(str);
52
+ },
53
+
16
54
  // Merge two maps nondestructively.
17
55
  merge: function(m1, m2) {
18
56
  return _.extend({}, m1, m2)
19
57
  },
20
-
58
+
21
59
  // Wraps a function in another, which calls f at most once every period
22
60
  // milliseconds. Tries to minimize latency.
23
61
  slur: function(period, f) {
@@ -3,7 +3,7 @@ var view = (function() {
3
3
  var focused = null;
4
4
  var focusOverlay = $('<div class="focusOverlay"></div>');
5
5
  $('body').append(focusOverlay);
6
-
6
+
7
7
  // Unfocus all views.
8
8
  var unfocus = function() {
9
9
  if (focused) {
@@ -19,8 +19,8 @@ var view = (function() {
19
19
  }
20
20
 
21
21
  function inherit(sup, sub) {
22
- var newSubPrototype = createObject(sup.prototype);
23
- newSubPrototype.constructor = sub;
22
+ var newSubPrototype = createObject(sup.prototype);
23
+ newSubPrototype.constructor = sub;
24
24
  sub.prototype = newSubPrototype;
25
25
  }
26
26
 
@@ -29,12 +29,12 @@ var view = (function() {
29
29
  var t = types[json.type];
30
30
  return(new t(json));
31
31
  }
32
-
32
+
33
33
  // Initialize keybindings
34
34
  function setKeyBindings() {
35
35
  var focusedBindings = {
36
36
  // left
37
- 37: function(ev) {
37
+ 37: function(ev) {
38
38
  if (ev.ctrlKey === true) {
39
39
  focused.split('HStack', -1);
40
40
  } else {
@@ -49,8 +49,8 @@ var view = (function() {
49
49
  } else {
50
50
  focused.moveVertical(-1);
51
51
  }
52
- },
53
-
52
+ },
53
+
54
54
  // right
55
55
  39: function(ev) {
56
56
  if (ev.ctrlKey === true) {
@@ -58,17 +58,17 @@ var view = (function() {
58
58
  } else {
59
59
  focused.moveHorizontal(1);
60
60
  }
61
- },
62
-
61
+ },
62
+
63
63
  // down
64
- 40: function(ev) {
64
+ 40: function(ev) {
65
65
  if (ev.ctrlKey === true) {
66
66
  focused.split('VStack', 1);
67
67
  } else {
68
68
  focused.moveVertical(1);
69
69
  }
70
70
  },
71
-
71
+
72
72
  27: function() { focused.unfocus() }, // escape
73
73
  33: function() { if (focused.parent) { // pgup
74
74
  focused.parent.focus();
@@ -84,7 +84,7 @@ var view = (function() {
84
84
  189: function() { focused.shrink(); }, // -
85
85
  107: function() { focused.grow(); }, // + (NumPad)
86
86
  109: function() { focused.shrink(); } // - (NumPad)
87
-
87
+
88
88
  };
89
89
 
90
90
  var bindings = {};
@@ -112,6 +112,8 @@ var view = (function() {
112
112
  // View ////////////////////////////////////////////////////////////////////
113
113
 
114
114
  var View = function(json) {
115
+ this.id = json.id || util.uniqueId();
116
+ this.version = json.version || 0;
115
117
  this.type = json.type;
116
118
  this.el = $('<div class="view">');
117
119
  this.weight = json.weight || 1;
@@ -122,10 +124,13 @@ var view = (function() {
122
124
 
123
125
  var self = this;
124
126
  this.clickFocusable = true;
125
- this.el.click(function() {
126
- if (self.clickFocusable) {
127
- self.focus();
128
- }
127
+ this.el.click(function(e) {
128
+ if (!e) var e = windows.event;
129
+ if (e.ctrlKey || e.metaKey) {
130
+ if (self.clickFocusable) {
131
+ self.focus();
132
+ }
133
+ }
129
134
  });
130
135
  };
131
136
  types.View = View;
@@ -162,19 +167,28 @@ var view = (function() {
162
167
  }
163
168
  };
164
169
 
170
+ View.prototype.bumpVersion = function() {
171
+ this.version = (this.version + 1) || 1;
172
+ if (this.parent) {
173
+ this.parent.bumpVersion();
174
+ }
175
+ };
176
+
165
177
  View.prototype.reflow = function() {
166
178
  };
167
179
 
168
180
  View.prototype.grow = function() {
169
181
  this.weight *= 2;
170
- this.parent.reflow();
182
+ this.parent.reflow();
171
183
  focused.refocus();
184
+ this.bumpVersion();
172
185
  };
173
186
 
174
187
  View.prototype.shrink = function() {
175
188
  this.weight *= 0.5;
176
189
  this.parent.reflow();
177
190
  focused.refocus();
191
+ this.bumpVersion();
178
192
  };
179
193
 
180
194
  // Replace this view with a different one. Returns replacement.
@@ -186,7 +200,7 @@ var view = (function() {
186
200
  if (p == null) {
187
201
  throw "Sorry, can't replace top-level views.";
188
202
  }
189
-
203
+
190
204
  if (p.replaceChild == null) {
191
205
  throw "Sorry, can't replace unless parent can replace child.";
192
206
  }
@@ -226,7 +240,7 @@ var view = (function() {
226
240
  // new view before us) or +1 (place the new view after us).
227
241
  View.prototype.splitParentStack = function(i) {
228
242
  console.log("Split parent");
229
- if (i === null) { i = 0 }
243
+ if (i === null) { i = 0 }
230
244
  var index = this.parent.indexOf(this) - Math.min(i, 0);
231
245
  console.log(this.parent.indexOf(this), index);
232
246
  this.parent.insertChild(
@@ -251,7 +265,7 @@ var view = (function() {
251
265
  weight: this.weight
252
266
  });
253
267
  parent.replaceChild(this, stack);
254
-
268
+
255
269
  // Add self to stack
256
270
  this.weight = 1;
257
271
  if (i === -1) {
@@ -318,7 +332,7 @@ var view = (function() {
318
332
  return null;
319
333
  }
320
334
  }
321
-
335
+
322
336
  // Returns the nearest parent vstack
323
337
  View.prototype.enclosingVStack = function() {
324
338
  try {
@@ -363,6 +377,7 @@ var view = (function() {
363
377
  neighbor.addChild(this);
364
378
  neighbor.reflow();
365
379
  this.focus();
380
+ this.bumpVersion();
366
381
  return;
367
382
  }
368
383
  }
@@ -374,17 +389,18 @@ var view = (function() {
374
389
  // left. Nothing *needs* to happen, so we return immediately.
375
390
  return;
376
391
  }
377
-
392
+
378
393
  // We're moving to a new position inside the enclosing stack.
379
394
  this.removeFromParent();
380
395
  stack.insertChild(newI, this);
381
396
  stack.reflow();
382
397
  this.focus();
398
+ this.bumpVersion();
383
399
  } else {
384
400
  console.log("Sorry, not yet");
385
401
  }
386
402
  }
387
-
403
+
388
404
  View.prototype.moveHorizontal = function(delta) {
389
405
  this.move('enclosingHStack', delta);
390
406
  }
@@ -406,7 +422,7 @@ var view = (function() {
406
422
  '<button name="apply">Apply</button>' +
407
423
  '</form></div>');
408
424
  dialog.find('h1').text("Edit " + this.type);
409
-
425
+
410
426
  // The serialized representation of a view that we're editing.
411
427
  // Carried between various view types; when Apply is clicked, projected
412
428
  // into an actual view.
@@ -446,7 +462,7 @@ var view = (function() {
446
462
  });
447
463
 
448
464
  // Apply button.
449
- var me = this;
465
+ var me = this;
450
466
  dialog.find('button[name=apply]').click(function(e) {
451
467
  // Don't submit the form.
452
468
  e.preventDefault();
@@ -457,7 +473,12 @@ var view = (function() {
457
473
  // Replace view.
458
474
  delete replacementJson.virtual;
459
475
  replacement = me.replace(reify(replacementJson));
476
+ replacement.bumpVersion();
477
+
478
+ // Reflow
460
479
  replacement.parent.reflow();
480
+
481
+ // Clean up view
461
482
  me.delete();
462
483
  replacement.focus();
463
484
 
@@ -467,7 +488,7 @@ var view = (function() {
467
488
 
468
489
  // Show dialog.
469
490
  keys.disable();
470
- dialog.modal({onClose: function() {
491
+ dialog.modal({onClose: function() {
471
492
  keys.enable();
472
493
  $.modal.close();
473
494
  }});
@@ -475,7 +496,10 @@ var view = (function() {
475
496
 
476
497
  // Serialize this view to JSON.
477
498
  View.prototype.json = function() {
478
- return {type: 'View', weight: this.weight};
499
+ return {type: 'View',
500
+ weight: this.weight,
501
+ id: this.id,
502
+ version: this.version};
479
503
  }
480
504
 
481
505
  // Balloon /////////////////////////////////////////////////////////////////
@@ -486,7 +510,7 @@ var view = (function() {
486
510
  this.clickFocusable = false;
487
511
  this.el.detach();
488
512
  this.el.appendTo(this.container);
489
-
513
+
490
514
  this.child = reify(json.child);
491
515
  this.child.parent = this;
492
516
  this.el.append(this.child.el);
@@ -504,7 +528,7 @@ var view = (function() {
504
528
  Balloon.prototype.replaceChild = function(v1, v2) {
505
529
  this.child.parent = null;
506
530
  this.child.el.detach();
507
-
531
+
508
532
  this.child = v2;
509
533
  v2.parent = this;
510
534
  this.el.append(this.child.el);
@@ -668,13 +692,13 @@ var view = (function() {
668
692
  };
669
693
  inherit(Stack, VStack);
670
694
  types.VStack = VStack;
671
-
695
+
672
696
  VStack.prototype.json = function() {
673
697
  return $.extend(Stack.prototype.json.call(this), {type: 'VStack'});
674
698
  }
675
-
699
+
676
700
  VStack.prototype.isVStack = true;
677
-
701
+
678
702
  VStack.prototype.reflow = function() {
679
703
  if (this.el === null) {
680
704
  // We're gone.
@@ -5,6 +5,7 @@
5
5
  view.View.call(this, json);
6
6
  this.query = json.query;
7
7
  this.title = json.title;
8
+ this.max = json.max || null;
8
9
  this.graphType = json.graphType || 'line';
9
10
  this.stackMode = json.stackMode || 'false';
10
11
  this.lineWidth = json.lineWidth || 1;
@@ -94,6 +95,7 @@
94
95
  yaxis: {
95
96
  font: this.font,
96
97
  min: 0,
98
+ max: this.max
97
99
  },
98
100
  xaxis: {
99
101
  font: this.font,
@@ -239,6 +241,7 @@
239
241
  type: 'Flot',
240
242
  title: this.title,
241
243
  query: this.query,
244
+ max: this.max,
242
245
  timeRange: this.timeRange / 1000,
243
246
  graphType: this.graphType,
244
247
  stackMode: this.stackMode
@@ -262,7 +265,9 @@
262
265
  '<label for="query">query</label>' +
263
266
  '<textarea type="text" class="query" name="query">{{ query }}</textarea><br />' +
264
267
  '<label for="timeRange">Time range (s)</label>' +
265
- '<input type="text" name="timeRange" value="{{timeRange / 1000}}" />'
268
+ '<input type="text" name="timeRange" value="{{timeRange / 1000}}" />' +
269
+ '<label for="max">Max</label>' +
270
+ '<input type="text" name="max" value="{{max}}" />'
266
271
  );
267
272
 
268
273
  // Returns the edit form
@@ -2,11 +2,19 @@
2
2
  var fitopts = {min: 6, max: 1000};
3
3
 
4
4
  var Gauge = function(json) {
5
+ // Init
5
6
  view.View.call(this, json);
7
+ this.clickFocusable = true;
8
+
9
+ // Config
6
10
  this.query = json.query;
7
11
  this.title = json.title;
8
12
  this.commaSeparateThousands = json.commaSeparateThousands;
9
- this.clickFocusable = true;
13
+
14
+ // State
15
+ this.currentEvent = null;
16
+
17
+ // HTML
10
18
  this.el.addClass('gauge');
11
19
  this.el.append(
12
20
  '<div class="box">' +
@@ -18,11 +26,16 @@
18
26
  this.box = this.el.find('.box');
19
27
  this.el.find('h2').text(this.title);
20
28
 
29
+ // When clicked, display event
30
+ var self = this;
31
+ this.box.click(function() { eventPane.show(self.currentEvent) });
32
+
21
33
  if (this.query) {
22
34
  var reflowed = false;
23
35
  var me = this;
24
36
  var value = this.el.find('.value');
25
37
  this.sub = subs.subscribe(this.query, function(e) {
38
+ self.currentEvent = e;
26
39
  me.box.attr('class', 'box state ' + e.state);
27
40
  value.text(format.float(e.metric, 2, me.commaSeparateThousands));
28
41
  value.attr('title', e.description);