fnordmetric 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +1 -0
- data/VERSION +1 -1
- data/doc/preview1.png +0 -0
- data/doc/preview2.png +0 -0
- data/doc/ulm_stats.rb +622 -0
- data/doc/version +1 -0
- data/fnordmetric.gemspec +16 -38
- data/haml/app.haml +12 -5
- data/lib/fnordmetric.rb +3 -0
- data/lib/fnordmetric/app.rb +19 -10
- data/lib/fnordmetric/bars_widget.rb +26 -0
- data/lib/fnordmetric/context.rb +3 -3
- data/lib/fnordmetric/gauge.rb +20 -0
- data/lib/fnordmetric/gauge_calculations.rb +28 -4
- data/lib/fnordmetric/gauge_modifiers.rb +39 -6
- data/lib/fnordmetric/logger.rb +19 -0
- data/lib/fnordmetric/numbers_widget.rb +5 -15
- data/lib/fnordmetric/pie_widget.rb +23 -0
- data/lib/fnordmetric/standalone.rb +1 -1
- data/lib/fnordmetric/timeline_widget.rb +16 -23
- data/lib/fnordmetric/toplist_widget.rb +25 -0
- data/lib/fnordmetric/widget.rb +3 -3
- data/pub/{fnordmetric/fnordmetric.css → fnordmetric.css} +46 -36
- data/pub/fnordmetric.js +1069 -0
- data/pub/loader.gif +0 -0
- data/pub/{highcharts → vendor}/highcharts.js +0 -0
- data/pub/{jquery-1.6.1.min.js → vendor/jquery-1.6.1.min.js} +0 -0
- data/readme.rdoc +228 -311
- data/spec/app_spec.rb +63 -3
- data/spec/gauge_modifiers_spec.rb +157 -2
- data/spec/gauge_spec.rb +143 -12
- data/spec/widget_spec.rb +18 -18
- metadata +33 -58
- data/.document +0 -5
- data/_spec/app_spec.rb +0 -178
- data/_spec/cache_spec.rb +0 -53
- data/_spec/combine_metric_spec.rb +0 -19
- data/_spec/core_spec.rb +0 -50
- data/_spec/count_metric_spec.rb +0 -32
- data/_spec/dashboard_spec.rb +0 -67
- data/_spec/event_spec.rb +0 -46
- data/_spec/metric_spec.rb +0 -118
- data/_spec/report_spec.rb +0 -87
- data/_spec/sum_metric_spec.rb +0 -33
- data/_spec/widget_spec.rb +0 -107
- data/doc/example_server.rb +0 -56
- data/doc/import_dump.rb +0 -26
- data/pub/fnordmetric/fnordmetric.js +0 -543
- data/pub/fnordmetric/widget_numbers.js +0 -71
- data/pub/fnordmetric/widget_timeline.css +0 -0
- data/pub/fnordmetric/widget_timeline.js +0 -110
- data/pub/highcharts/adapters/mootools-adapter.js +0 -12
- data/pub/highcharts/adapters/mootools-adapter.src.js +0 -243
- data/pub/highcharts/adapters/prototype-adapter.js +0 -14
- data/pub/highcharts/adapters/prototype-adapter.src.js +0 -284
- data/pub/highcharts/highcharts.src.js +0 -11103
- data/pub/highcharts/modules/exporting.js +0 -22
- data/pub/highcharts/modules/exporting.src.js +0 -703
- data/pub/highcharts/themes/dark-blue.js +0 -268
- data/pub/highcharts/themes/dark-green.js +0 -268
- data/pub/highcharts/themes/gray.js +0 -262
- data/pub/highcharts/themes/grid.js +0 -97
- data/pub/raphael-min.js +0 -8
- data/pub/raphael-utils.js +0 -221
- data/ulm_stats.rb +0 -198
@@ -0,0 +1,23 @@
|
|
1
|
+
class FnordMetric::PieWidget < FnordMetric::Widget
|
2
|
+
|
3
|
+
def data
|
4
|
+
super.merge(
|
5
|
+
:gauges => gauges.map(&:name),
|
6
|
+
:gauge_titles => gauge_titles,
|
7
|
+
:autoupdate => (@opts[:autoupdate] || 60)
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def gauge_titles
|
12
|
+
{}.tap do |_hash|
|
13
|
+
gauges.each do |gauge|
|
14
|
+
_hash.merge!(gauge.name => gauge.title)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_tick?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -1,35 +1,28 @@
|
|
1
1
|
class FnordMetric::TimelineWidget < FnordMetric::Widget
|
2
2
|
|
3
|
-
def data_labels
|
4
|
-
ticks.map do |t|
|
5
|
-
Time.at(t).strftime('%d.%m.%y %H:%M')
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def data_series
|
10
|
-
gauges.map do |gauge|
|
11
|
-
{
|
12
|
-
:color => next_series_colour,
|
13
|
-
:data => ticks.map{ |t| gauge.value_at(t)||0 }
|
14
|
-
}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def next_series_colour
|
19
|
-
@series_colors.pop.tap do |color|
|
20
|
-
@series_colors.unshift(color)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
3
|
def data
|
25
4
|
@series_colors = ["#FACE4F", "#42436B", "#CD645A", "#2F635E"]
|
26
5
|
|
27
6
|
super.merge(
|
28
|
-
:
|
29
|
-
:
|
7
|
+
:gauges => gauges.map(&:name),
|
8
|
+
:gauge_titles => gauge_titles,
|
9
|
+
:start_timestamp => ticks.first,
|
10
|
+
:end_timestamp => ticks.last,
|
11
|
+
:autoupdate => (@opts[:autoupdate] || 60),
|
12
|
+
:include_current => !!@opts[:include_current],
|
13
|
+
:plot_style => (@opts[:plot_style] || 'line'),
|
14
|
+
:tick => tick
|
30
15
|
)
|
31
16
|
end
|
32
17
|
|
18
|
+
def gauge_titles
|
19
|
+
{}.tap do |_hash|
|
20
|
+
gauges.each do |gauge|
|
21
|
+
_hash.merge!(gauge.name => gauge.title)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
33
26
|
def has_tick?
|
34
27
|
true
|
35
28
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class FnordMetric::ToplistWidget < FnordMetric::Widget
|
2
|
+
|
3
|
+
def data
|
4
|
+
super.merge(
|
5
|
+
:gauges => data_gauges,
|
6
|
+
:autoupdate => (@opts[:autoupdate] || 0)
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
def data_gauges
|
11
|
+
Hash.new.tap do |hash|
|
12
|
+
gauges.each do |g|
|
13
|
+
hash[g.name] = {
|
14
|
+
:tick => g.tick,
|
15
|
+
:title => g.title
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_tick?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/fnordmetric/widget.rb
CHANGED
@@ -29,7 +29,7 @@ class FnordMetric::Widget
|
|
29
29
|
|
30
30
|
if (ticks = gauges.map{ |g| g.tick }).uniq.length == 1
|
31
31
|
@tick = ticks.first
|
32
|
-
|
32
|
+
elsif !!self.try(:has_tick?)
|
33
33
|
error! "you can't add gauges with different ticks to the same widget"
|
34
34
|
end
|
35
35
|
end
|
@@ -52,8 +52,8 @@ class FnordMetric::Widget
|
|
52
52
|
def default_range(now=Time.now)
|
53
53
|
ensure_has_tick!
|
54
54
|
te = gauges.first.tick_at(now.to_i)
|
55
|
-
te
|
56
|
-
rs = @tick == 1.hour.to_i ? 24 : 30
|
55
|
+
te -= @tick unless include_current?
|
56
|
+
rs = (@opts[:ticks] || (@tick == 1.hour.to_i ? 24 : 30)).to_i
|
57
57
|
(te-(@tick*rs)..te)
|
58
58
|
end
|
59
59
|
|
@@ -24,24 +24,53 @@ body{ background:#3b3e45; color:#333; margin:0; padding:0; overflow-y:scroll; fo
|
|
24
24
|
.widget{ min-height:100px; border-right:1px solid #ececec; float:left; }
|
25
25
|
.widget.full_width{ border-right:none; }
|
26
26
|
.widget .inner{ margin:20px; }
|
27
|
-
|
27
|
+
/*.widget .headbar{ margin-bottom:30px; }*/
|
28
28
|
|
29
|
-
|
30
|
-
.
|
31
|
-
.headbar h2{ margin:8px; line-height:21px; float:left; height:20px; font-size:14px; }
|
32
|
-
.headbar .datepicker{ background:#fff; border:1px solid #999; height:20px; padding:0 7px; float:right; margin:8px -1px; min-width:100px; font-size:11px; font-style:italic; }
|
33
|
-
.headbar .button.mr{ margin-right:16px; }
|
29
|
+
.toplist_inner{ min-height:300px; }
|
30
|
+
.toplist_inner.loading{ opacity:0.5; background:url('/loader.gif') no-repeat center center; }
|
34
31
|
|
32
|
+
.toplist_item{ border-bottom:1px solid #dedede; height:42px; }
|
33
|
+
.toplist_item .title{ float:left; line-height:42px; margin-left:20px; font-size:13px; color:#333; }
|
34
|
+
.toplist_item .value{ float:right; line-height:42px; margin-right:20px; font-size:13px; font-weight:bold; color:#333; width:70px; color:#666; }
|
35
|
+
.toplist_item .percent{ float:right; line-height:42px; margin-right:20px; font-size:18px; font-weight:bold; color:#333; width:70px; }
|
36
|
+
|
37
|
+
.headbar {
|
38
|
+
|
39
|
+
height:36px;
|
40
|
+
background-color: #F4F4F4;
|
41
|
+
background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#e9e9e9));
|
42
|
+
background-image: -webkit-linear-gradient(top, #f4f4f4, #e9e9e9);
|
43
|
+
background-image: -moz-linear-gradient(top, #f4f4f4, #e9e9e9);
|
44
|
+
background-image: -ms-linear-gradient(top, #f4f4f4, #e9e9e9);
|
45
|
+
background-image: -o-linear-gradient(top, #f4f4f4, #e9e9e9);
|
46
|
+
background-image: linear-gradient(top, #f4f4f4, #e9e9e9);
|
47
|
+
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f4f4f4', EndColorStr='#e9e9e9');
|
48
|
+
padding: 0 15px;
|
49
|
+
border-bottom: 1px solid #C9C9C9;
|
50
|
+
border-top: 1px solid #d0d0d0;
|
51
|
+
font-size:13px;
|
52
|
+
line-height:29px;
|
53
|
+
text-shadow: 1px 0px 2px rgba(255, 255, 255, 1);
|
54
|
+
-moz-text-shadow: 1px 0px 2px rgba(255,255,255,1);
|
55
|
+
-webkit-text-shadow: 1px 0px 2px rgba(255,255,255,1);
|
56
|
+
overflow:hidden;
|
57
|
+
}
|
58
|
+
|
59
|
+
.headbar.small{ height:29px; }
|
60
|
+
|
61
|
+
.headbar h2{ line-height:37px; margin:0; float:left; font-size:14px; }
|
62
|
+
.headbar .datepicker{ background:#fff; border:1px solid #999; height:20px; padding:0 7px; float:right; margin:8px -1px; min-width:100px; font-size:11px; font-style:italic; line-height:21px; }
|
63
|
+
.headbar .button.mr{ margin-right:16px; }
|
35
64
|
|
36
65
|
.headbar .button{
|
37
66
|
margin:8px 0px; height:16px; float:right; display:block;
|
38
67
|
margin-right:-1px;
|
39
|
-
background:url('/
|
68
|
+
background:url('/sprite.png') no-repeat 0 -49px #eee;
|
40
69
|
border:1px solid #999;
|
41
70
|
border-bottom-color:#888;
|
42
71
|
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .1);
|
43
72
|
cursor:pointer;
|
44
|
-
|
73
|
+
border-radius:3px;
|
45
74
|
font-size: 11px;
|
46
75
|
font-weight:bold;
|
47
76
|
line-height:16px;
|
@@ -53,36 +82,16 @@ body{ background:#3b3e45; color:#333; margin:0; padding:0; overflow-y:scroll; fo
|
|
53
82
|
}
|
54
83
|
|
55
84
|
.headbar .button:hover, .headbar.button.active{background:#ddd;border-bottom-color:#999;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, .05)}
|
56
|
-
*/
|
57
|
-
.numbers_container, .number{ float:left; border-right:1px solid #ececec; }
|
58
|
-
.number{ margin-left:12px; padding-right:20px; margin-right:10px; }
|
59
|
-
.number .value{ color:#333; font-size:30px; display:block; margin-bottom:5px; }
|
60
|
-
.number .desc{ color:#999; font-size:12px; }
|
61
|
-
.number:last-child{ border-right:none; }
|
62
|
-
.numbers_container{ padding-right:0px; width:33.2%; }
|
63
|
-
|
64
|
-
.numbers_container .title{ padding:4px 10px 1px 10px; color:#333; font-size:13px; display:block; background:#f2f2f2; border-bottom:1px solid #e2e2e2; margin-bottom:15px; }
|
65
85
|
|
66
86
|
|
67
|
-
.
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f4f4f4', EndColorStr='#e9e9e9');
|
76
|
-
padding: 0 15px;
|
77
|
-
border-bottom: 1px solid #C9C9C9;
|
78
|
-
border-top: 1px solid #F9F9F9;
|
79
|
-
height: 28px;
|
80
|
-
font-size:13px;
|
81
|
-
line-height:29px;
|
82
|
-
text-shadow: 1px 0px 2px rgba(255, 255, 255, 1);
|
83
|
-
-moz-text-shadow: 1px 0px 2px rgba(255,255,255,1);
|
84
|
-
-webkit-text-shadow: 1px 0px 2px rgba(255,255,255,1);
|
85
|
-
}
|
87
|
+
.numbers_container, .number{ float:left; width:60px; }
|
88
|
+
.number{ padding-right:20px; margin-right:6px; }
|
89
|
+
.number .value{ color:#444; font-size:20px; display:block; margin-bottom:5px; font-weight:bold; }
|
90
|
+
.number .desc{ color:#999; font-size:12px; margin-bottom:5px; display:block; white-space:nowrap; }
|
91
|
+
.number:last-child{ border-right:none; }
|
92
|
+
.numbers_container{ padding-right:0px; width:215px; float:left; margin:15px 0 -1px 20px; padding-bottom:5px; border-bottom:1px solid #dedede; }
|
93
|
+
.numbers_container.size_3{ width:258px; }
|
94
|
+
.numbers_container .title{ padding:4px 0 1px 0; color:#333; font-size:14px; display:block;font-weight:400; }
|
86
95
|
|
87
96
|
|
88
97
|
ul.session_list{ list-style-type:none; margin:0; padding:9px 16px 0 11px; }
|
@@ -118,3 +127,4 @@ ul.event_type_list li .history:hover{ color:#333; text-decoration:underline; }
|
|
118
127
|
height: 0;
|
119
128
|
}
|
120
129
|
|
130
|
+
.highcharts-series circle{ stroke-width:1px; }
|
data/pub/fnordmetric.js
ADDED
@@ -0,0 +1,1069 @@
|
|
1
|
+
var FnordMetric = (function(){
|
2
|
+
|
3
|
+
var canvasElem = false;
|
4
|
+
|
5
|
+
var currentNamespace = false;
|
6
|
+
var currentView = false;
|
7
|
+
var currentWidgetUID=23;
|
8
|
+
|
9
|
+
function decPrint(val){
|
10
|
+
return (val < 10 ? '0'+val : val);
|
11
|
+
}
|
12
|
+
|
13
|
+
function formatTimeOfDay(_time){
|
14
|
+
var time = new Date();
|
15
|
+
time.setTime(_time*1000);
|
16
|
+
return decPrint(time.getHours()) + ':' +
|
17
|
+
decPrint(time.getMinutes()) + ':' +
|
18
|
+
decPrint(time.getSeconds());
|
19
|
+
}
|
20
|
+
|
21
|
+
function formatTimeRange(range){
|
22
|
+
if (range < 60){
|
23
|
+
return parseInt(range) + ' sec';
|
24
|
+
} else if(range<3600){
|
25
|
+
return parseInt(range/60) + ' min';
|
26
|
+
} else if(range==3600){
|
27
|
+
return '1 hour';
|
28
|
+
} else if(range<(3600*24)){
|
29
|
+
return parseInt(range/3600) + ' hours';
|
30
|
+
} else if(range==(3600*24)){
|
31
|
+
return '1 day';
|
32
|
+
} else {
|
33
|
+
return parseInt(range/(3600*24)) + ' days';
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
function formatTimeSince(time){
|
38
|
+
var now = new Date().getTime()/1000;
|
39
|
+
var since = now - time;
|
40
|
+
return formatTimeRange(since);
|
41
|
+
}
|
42
|
+
|
43
|
+
function formatOffset(offset, next_offset){
|
44
|
+
if((offset == 0) && (next_offset==(3600*24))){
|
45
|
+
return 'today';
|
46
|
+
} if((offset == 0) && (next_offset==3600)){
|
47
|
+
return 'this hour';
|
48
|
+
} else if(offset == 0){
|
49
|
+
return 'last ' + formatTimeRange(next_offset||0);
|
50
|
+
} else if(offset==(3600*24)){
|
51
|
+
return 'yesterday';
|
52
|
+
} else if(offset==3600){
|
53
|
+
return 'last hour';
|
54
|
+
} else {
|
55
|
+
return formatTimeRange(offset) + ' ago';
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
function formatValue(value){
|
60
|
+
if(value < 10){
|
61
|
+
return value.toFixed(2);
|
62
|
+
} else if(value > 1000){
|
63
|
+
return (value/1000.0).toFixed(1) + "k";
|
64
|
+
} else {
|
65
|
+
return value.toFixed(0);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
function getNextWidgetUID(){
|
70
|
+
return (currentWidgetUID += 1);
|
71
|
+
}
|
72
|
+
|
73
|
+
var toplistWidget = function(){
|
74
|
+
|
75
|
+
function render(opts){
|
76
|
+
|
77
|
+
var current_gauge = false;
|
78
|
+
|
79
|
+
var headbar = $('<div class="headbar"></div>').append(
|
80
|
+
$('<h2></h2>').html(opts.title)
|
81
|
+
);
|
82
|
+
|
83
|
+
opts.elem.append(headbar).css({
|
84
|
+
'marginBottom': 20,
|
85
|
+
'overflow': 'hidden'
|
86
|
+
}).append(
|
87
|
+
$('<div class="toplist_inner"></div>')
|
88
|
+
);
|
89
|
+
|
90
|
+
var first = true;
|
91
|
+
for(k in opts.gauges){
|
92
|
+
headbar.append(
|
93
|
+
$('<div></div>')
|
94
|
+
.attr('class', 'button mr')
|
95
|
+
.attr('rel', k)
|
96
|
+
.append(
|
97
|
+
$('<span></span>').html(opts.gauges[k].title)
|
98
|
+
).click(function(){
|
99
|
+
loadGauge($(this).attr('rel'));
|
100
|
+
}
|
101
|
+
)
|
102
|
+
);
|
103
|
+
if(first){
|
104
|
+
first = false;
|
105
|
+
loadGauge(k);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
if(opts.autoupdate){
|
110
|
+
var secs = parseInt(opts.autoupdate);
|
111
|
+
if(secs > 0){
|
112
|
+
|
113
|
+
var autoupdate_interval = window.setInterval(function(){
|
114
|
+
loadGauge(false, true);
|
115
|
+
}, secs*1000);
|
116
|
+
|
117
|
+
$('body').bind('fm_dashboard_close', function(){
|
118
|
+
window.clearInterval(autoupdate_interval);
|
119
|
+
});
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
123
|
+
function loadGauge(gkey, silent){
|
124
|
+
if(!gkey){ gkey = current_gauge; }
|
125
|
+
current_gauge = gkey;
|
126
|
+
if(!silent){ $('.toplist_inner', opts.elem).addClass('loading'); }
|
127
|
+
var _url = '/' + currentNamespace + '/gauge/' + gkey;
|
128
|
+
$.get(_url, function(_resp){
|
129
|
+
var resp = JSON.parse(_resp);
|
130
|
+
renderGauge(gkey, resp);
|
131
|
+
})
|
132
|
+
}
|
133
|
+
|
134
|
+
function renderGauge(gkey, gdata){
|
135
|
+
var _elem = $('.toplist_inner', opts.elem).removeClass('loading').html('');
|
136
|
+
$(gdata.values).each(function(n, _gd){
|
137
|
+
var _perc = (parseInt(gdata.values[n][1]) / parseFloat(gdata.count))*100;
|
138
|
+
var _item = $('<div class="toplist_item"><div class="title"></div><div class="value"></div><div class="percent"></div></div>');
|
139
|
+
$('.title', _item).html(gdata.values[n][0]);
|
140
|
+
$('.value', _item).html(formatValue(parseInt(gdata.values[n][1])));
|
141
|
+
$('.percent', _item).html(_perc.toFixed(1) + '%');
|
142
|
+
_elem.append(_item);
|
143
|
+
});
|
144
|
+
}
|
145
|
+
|
146
|
+
}
|
147
|
+
|
148
|
+
|
149
|
+
return {
|
150
|
+
render: render
|
151
|
+
};
|
152
|
+
|
153
|
+
};
|
154
|
+
|
155
|
+
var numbersWidget = function(){
|
156
|
+
|
157
|
+
|
158
|
+
function render(opts){
|
159
|
+
|
160
|
+
opts.elem.append(
|
161
|
+
$('<div class="headbar small"></div>').html(opts.title)
|
162
|
+
).css({
|
163
|
+
'marginBottom': 20,
|
164
|
+
'overflow': 'hidden'
|
165
|
+
});
|
166
|
+
|
167
|
+
for(k in opts.gauges){
|
168
|
+
var gtick = parseInt(opts.gauges[k].tick);
|
169
|
+
var gtitle = opts.gauges[k].title;
|
170
|
+
|
171
|
+
var container = $('<div></div>')
|
172
|
+
.addClass('numbers_container')
|
173
|
+
.addClass('size_'+opts.offsets.length)
|
174
|
+
.attr('rel', k)
|
175
|
+
.append(
|
176
|
+
$('<div></div>')
|
177
|
+
.addClass('title')
|
178
|
+
.html(gtitle)
|
179
|
+
);
|
180
|
+
|
181
|
+
|
182
|
+
$(opts.offsets).each(function(n, offset){
|
183
|
+
var _off, _nextoff, _sum;
|
184
|
+
if (offset[0]=="s"){
|
185
|
+
_off = 0;
|
186
|
+
_sum = _nextoff = (gtick * parseInt(offset.slice(1)));
|
187
|
+
} else {
|
188
|
+
_sum = 0;
|
189
|
+
_off = offset*gtick;
|
190
|
+
_nextoff = gtick;
|
191
|
+
}
|
192
|
+
container.append(
|
193
|
+
$('<div></div>')
|
194
|
+
.addClass('number')
|
195
|
+
.attr('rel', k)
|
196
|
+
.attr('data-offset', _off)
|
197
|
+
.attr('data-sum', _sum)
|
198
|
+
.attr('data',0)
|
199
|
+
.append(
|
200
|
+
$('<span></span>').addClass('desc').html(formatOffset(_off, _nextoff))
|
201
|
+
)
|
202
|
+
.append(
|
203
|
+
$('<span></span>').addClass('value').html(0)
|
204
|
+
)
|
205
|
+
);
|
206
|
+
});
|
207
|
+
|
208
|
+
opts.elem.append(container);
|
209
|
+
}
|
210
|
+
|
211
|
+
if(opts.autoupdate){
|
212
|
+
var secs = parseInt(opts.autoupdate);
|
213
|
+
if(secs > 0){
|
214
|
+
|
215
|
+
var autoupdate_interval = window.setInterval(function(){
|
216
|
+
updateValues(opts);
|
217
|
+
}, secs*1000);
|
218
|
+
|
219
|
+
$('body').bind('fm_dashboard_close', function(){
|
220
|
+
window.clearInterval(autoupdate_interval);
|
221
|
+
});
|
222
|
+
|
223
|
+
}
|
224
|
+
|
225
|
+
};
|
226
|
+
|
227
|
+
updateValues(opts);
|
228
|
+
|
229
|
+
}
|
230
|
+
|
231
|
+
function updateValues(opts){
|
232
|
+
var values = $('.number', $(opts.elem));
|
233
|
+
var values_pending = values.length;
|
234
|
+
values.each(function(){
|
235
|
+
var _sum = parseInt($(this).attr('data-sum'));
|
236
|
+
var num = this;
|
237
|
+
var at = parseInt(new Date().getTime()/1000);
|
238
|
+
var url = '/' + currentNamespace + '/gauge/' + $(this).attr('rel');
|
239
|
+
if(_sum > 0){
|
240
|
+
url += '?at='+(at-_sum)+'-'+at+'&sum=true';
|
241
|
+
} else {
|
242
|
+
at -= parseInt($(this).attr('data-offset'));
|
243
|
+
url += '?at='+at;
|
244
|
+
}
|
245
|
+
|
246
|
+
$.get(url, function(_resp){
|
247
|
+
var resp = JSON.parse(_resp);
|
248
|
+
for(_k in resp){
|
249
|
+
$(num).attr('data', (resp[_k]||0));
|
250
|
+
}
|
251
|
+
if((values_pending -= 1)==0){
|
252
|
+
updateDisplay(opts, 4);
|
253
|
+
}
|
254
|
+
});
|
255
|
+
});
|
256
|
+
}
|
257
|
+
|
258
|
+
function updateDisplay(opts, diff_factor){
|
259
|
+
var still_running = false;
|
260
|
+
$('.number', $(opts.elem)).each(function(){
|
261
|
+
var target_val = parseFloat($(this).attr('data'));
|
262
|
+
var current_val = parseFloat($(this).attr('data-current'));
|
263
|
+
if(!current_val){ current_val=0; }
|
264
|
+
var diff = (target_val-current_val)/diff_factor;
|
265
|
+
if(diff < 1){ diff=1; }
|
266
|
+
if(target_val > current_val){
|
267
|
+
still_running = true;
|
268
|
+
var new_val = current_val+diff;
|
269
|
+
if(new_val > target_val){ new_val = target_val; }
|
270
|
+
$(this).attr('data-current', new_val);
|
271
|
+
$('.value', this).html(formatValue(new_val));
|
272
|
+
}
|
273
|
+
});
|
274
|
+
if(still_running){
|
275
|
+
(function(df){
|
276
|
+
window.setTimeout(function(){ updateDisplay(opts, df); }, 30);
|
277
|
+
})(diff_factor);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
return {
|
282
|
+
render: render
|
283
|
+
};
|
284
|
+
|
285
|
+
};
|
286
|
+
|
287
|
+
var timelineWidget = function(){
|
288
|
+
|
289
|
+
function render(opts){
|
290
|
+
|
291
|
+
var widget_uid = getNextWidgetUID();
|
292
|
+
var chart=false;
|
293
|
+
var max_y=0;
|
294
|
+
|
295
|
+
function redrawWithRange(first_time, silent){
|
296
|
+
if(!silent){ $(opts.elem).css('opacity', 0.5); }
|
297
|
+
redrawDatepicker();
|
298
|
+
var _query = '?at='+opts.start_timestamp+'-'+opts.end_timestamp;
|
299
|
+
//chart.series = [];
|
300
|
+
max_y=0;
|
301
|
+
//metrics_completed = 0;
|
302
|
+
$(opts.gauges).each(function(i,gauge){
|
303
|
+
$.ajax({
|
304
|
+
url: '/'+currentNamespace+'/gauge/'+gauge+_query,
|
305
|
+
success: redrawGauge(first_time, gauge)
|
306
|
+
});
|
307
|
+
});
|
308
|
+
}
|
309
|
+
|
310
|
+
function redrawGauge(first_time, gauge){
|
311
|
+
return (function(json){
|
312
|
+
var raw_data = JSON.parse(json);
|
313
|
+
var series_data = [];
|
314
|
+
|
315
|
+
for(p in raw_data){
|
316
|
+
series_data.push([parseInt(p)*1000, raw_data[p]||0]);
|
317
|
+
max_y = Math.max(max_y, raw_data[p]);
|
318
|
+
}
|
319
|
+
|
320
|
+
if(!first_time){
|
321
|
+
chart.get('series-'+gauge).setData(series_data);
|
322
|
+
} else {
|
323
|
+
chart.addSeries({
|
324
|
+
name: opts.gauge_titles[gauge],
|
325
|
+
data: series_data,
|
326
|
+
id: 'series-'+gauge
|
327
|
+
});
|
328
|
+
}
|
329
|
+
|
330
|
+
chart.yAxis[0].setExtremes(0,max_y);
|
331
|
+
chart.redraw();
|
332
|
+
|
333
|
+
// shown on the *first* gauge load
|
334
|
+
$(opts.elem).css('opacity', 1);
|
335
|
+
});
|
336
|
+
}
|
337
|
+
|
338
|
+
function redrawDatepicker(){
|
339
|
+
$('.datepicker', opts.elem).html(
|
340
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(opts.start_timestamp)*1000) +
|
341
|
+
' ‐ ' +
|
342
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(opts.end_timestamp)*1000)
|
343
|
+
);
|
344
|
+
}
|
345
|
+
|
346
|
+
function moveRange(direction){
|
347
|
+
v = opts.tick*direction*8;
|
348
|
+
opts.start_timestamp += v;
|
349
|
+
opts.end_timestamp += v;
|
350
|
+
redrawWithRange();
|
351
|
+
}
|
352
|
+
|
353
|
+
function drawLayout(){
|
354
|
+
$(opts.elem).append( $('<div></div>').attr('class', 'headbar').append(
|
355
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('refresh')).click(
|
356
|
+
function(){ redrawWithRange(); }
|
357
|
+
)
|
358
|
+
).append(
|
359
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('→')).click(
|
360
|
+
function(){ moveRange(1); }
|
361
|
+
)
|
362
|
+
).append(
|
363
|
+
$('<div></div>').attr('class', 'datepicker')
|
364
|
+
).append(
|
365
|
+
$('<div></div>').attr('class', 'button').append($('<span></span>').html('←')).click(
|
366
|
+
function(){ moveRange(-1); }
|
367
|
+
)
|
368
|
+
).append(
|
369
|
+
$('<h2></h2>').html(opts.title)
|
370
|
+
) ).append(
|
371
|
+
$('<div></div>').attr('id', 'container-'+widget_uid).css({
|
372
|
+
height: 256,
|
373
|
+
marginBottom: 20,
|
374
|
+
overflow: 'hidden'
|
375
|
+
})
|
376
|
+
);
|
377
|
+
}
|
378
|
+
|
379
|
+
function drawChart(){
|
380
|
+
chart = new Highcharts.Chart({
|
381
|
+
chart: {
|
382
|
+
renderTo: 'container-'+widget_uid,
|
383
|
+
defaultSeriesType: opts.plot_style,
|
384
|
+
height: 270
|
385
|
+
},
|
386
|
+
series: [],
|
387
|
+
title: { text: '' },
|
388
|
+
xAxis: {
|
389
|
+
type: 'datetime',
|
390
|
+
tickInterval: opts.tick * 1000,
|
391
|
+
title: (opts.x_title||''),
|
392
|
+
labels: { step: 2 }
|
393
|
+
},
|
394
|
+
yAxis: {
|
395
|
+
title: (opts.y_title||''),
|
396
|
+
min: 0,
|
397
|
+
max: 1000
|
398
|
+
},
|
399
|
+
legend: {
|
400
|
+
layout: 'horizontal',
|
401
|
+
align: 'top',
|
402
|
+
verticalAlign: 'top',
|
403
|
+
x: -5,
|
404
|
+
y: -3,
|
405
|
+
margin: 25,
|
406
|
+
borderWidth: 0
|
407
|
+
},
|
408
|
+
plotOptions: {
|
409
|
+
line: {
|
410
|
+
shadow: false,
|
411
|
+
lineWidth: 3
|
412
|
+
}
|
413
|
+
}
|
414
|
+
});
|
415
|
+
}
|
416
|
+
|
417
|
+
drawLayout();
|
418
|
+
drawChart();
|
419
|
+
|
420
|
+
redrawWithRange(true);
|
421
|
+
|
422
|
+
if(opts.autoupdate){
|
423
|
+
var secs = parseInt(opts.autoupdate);
|
424
|
+
if(secs > 0){
|
425
|
+
|
426
|
+
var autoupdate_interval = window.setInterval(function(){
|
427
|
+
if(
|
428
|
+
(parseInt(new Date().getTime()/1000) - opts.end_timestamp) >
|
429
|
+
(opts.include_current ? 0 : opts.tick)
|
430
|
+
){
|
431
|
+
opts.end_timestamp += opts.tick;
|
432
|
+
opts.start_timestamp += opts.tick;
|
433
|
+
}
|
434
|
+
|
435
|
+
redrawWithRange(false, true);
|
436
|
+
}, secs*1000);
|
437
|
+
|
438
|
+
$('body').bind('fm_dashboard_close', function(){
|
439
|
+
window.clearInterval(autoupdate_interval);
|
440
|
+
});
|
441
|
+
|
442
|
+
}
|
443
|
+
};
|
444
|
+
|
445
|
+
}
|
446
|
+
|
447
|
+
return {
|
448
|
+
render: render
|
449
|
+
};
|
450
|
+
|
451
|
+
};
|
452
|
+
|
453
|
+
|
454
|
+
var barsWidget = function(){
|
455
|
+
|
456
|
+
function render(opts){
|
457
|
+
|
458
|
+
var widget_uid = getNextWidgetUID();
|
459
|
+
var chart=false;
|
460
|
+
var max_y=0;
|
461
|
+
|
462
|
+
function redraw(first_time, silent){
|
463
|
+
if(!silent){ $(opts.elem).css('opacity', 0.5); }
|
464
|
+
max_y=0;
|
465
|
+
$(opts.gauges).each(function(i,gauge){
|
466
|
+
$.ajax({
|
467
|
+
url: '/'+currentNamespace+'/gauge/'+gauge,
|
468
|
+
success: redrawGauge(first_time, gauge)
|
469
|
+
});
|
470
|
+
});
|
471
|
+
}
|
472
|
+
|
473
|
+
function redrawGauge(first_time, gauge){
|
474
|
+
return (function(json){
|
475
|
+
var raw_data = JSON.parse(json);
|
476
|
+
var series_data = [];
|
477
|
+
var series_type;
|
478
|
+
var label_data = [];
|
479
|
+
|
480
|
+
if(opts.plot_style == 'horizontal'){
|
481
|
+
series_type = 'bar';
|
482
|
+
} else {
|
483
|
+
series_type = 'column';
|
484
|
+
}
|
485
|
+
|
486
|
+
if(opts.order_by == 'field'){
|
487
|
+
raw_data.values.sort(function(a,b){
|
488
|
+
if(a[0] == b[0]){
|
489
|
+
return 0;
|
490
|
+
}else if(a[0] > b[0]){
|
491
|
+
return 1;
|
492
|
+
} else {
|
493
|
+
return -1;
|
494
|
+
}
|
495
|
+
});
|
496
|
+
}
|
497
|
+
|
498
|
+
for(p in raw_data.values){
|
499
|
+
label_data.push(raw_data.values[p][0]||'?');
|
500
|
+
series_data.push(parseInt(raw_data.values[p][1]||0));
|
501
|
+
//max_y = Math.max(max_y, raw_data[p]);
|
502
|
+
}
|
503
|
+
|
504
|
+
chart = new Highcharts.Chart({
|
505
|
+
chart: {
|
506
|
+
renderTo: 'container-'+widget_uid,
|
507
|
+
defaultSeriesType: series_type,
|
508
|
+
height: 270
|
509
|
+
},
|
510
|
+
title: { text: '' },
|
511
|
+
xAxis: {
|
512
|
+
categories: label_data
|
513
|
+
},
|
514
|
+
yAxis: {
|
515
|
+
title: { text: '' }
|
516
|
+
},
|
517
|
+
legend: {
|
518
|
+
layout: 'horizontal',
|
519
|
+
align: 'top',
|
520
|
+
verticalAlign: 'top',
|
521
|
+
x: -5,
|
522
|
+
y: -3,
|
523
|
+
margin: 25,
|
524
|
+
borderWidth: 0
|
525
|
+
},
|
526
|
+
plotOptions: {
|
527
|
+
column: {
|
528
|
+
animation: first_time,
|
529
|
+
}
|
530
|
+
},
|
531
|
+
series: [
|
532
|
+
{
|
533
|
+
name: opts.gauge_titles[gauge],
|
534
|
+
data: series_data
|
535
|
+
}
|
536
|
+
]
|
537
|
+
});
|
538
|
+
|
539
|
+
//chart.redraw();
|
540
|
+
$(opts.elem).css('opacity', 1);
|
541
|
+
});
|
542
|
+
}
|
543
|
+
|
544
|
+
function drawLayout(){
|
545
|
+
$(opts.elem).append( $('<div></div>').attr('class', 'headbar').append(
|
546
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('refresh')).click(
|
547
|
+
function(){ redraw(); }
|
548
|
+
)
|
549
|
+
).append(
|
550
|
+
$('<h2></h2>').html(opts.title)
|
551
|
+
) ).append(
|
552
|
+
$('<div></div>').attr('id', 'container-'+widget_uid).css({
|
553
|
+
height: 256,
|
554
|
+
marginBottom: 20,
|
555
|
+
overflow: 'hidden'
|
556
|
+
})
|
557
|
+
);
|
558
|
+
}
|
559
|
+
|
560
|
+
drawLayout();
|
561
|
+
redraw(true);
|
562
|
+
|
563
|
+
if(opts.autoupdate){
|
564
|
+
var autoupdate_interval = window.setInterval(function(){
|
565
|
+
redraw(false, true);
|
566
|
+
}, opts.autoupdate*1000);
|
567
|
+
|
568
|
+
$('body').bind('fm_dashboard_close', function(){
|
569
|
+
window.clearInterval(autoupdate_interval);
|
570
|
+
});
|
571
|
+
}
|
572
|
+
|
573
|
+
}
|
574
|
+
|
575
|
+
return {
|
576
|
+
render: render
|
577
|
+
};
|
578
|
+
|
579
|
+
};
|
580
|
+
|
581
|
+
|
582
|
+
var pieWidget = function(){
|
583
|
+
|
584
|
+
function render(opts){
|
585
|
+
|
586
|
+
var widget_uid = getNextWidgetUID();
|
587
|
+
var chart=false;
|
588
|
+
|
589
|
+
function redraw(first_time, silent){
|
590
|
+
if(!silent){ $(opts.elem).css('opacity', 0.5); }
|
591
|
+
var gauge_values = {};
|
592
|
+
var gauges_left = opts.gauges.length;
|
593
|
+
var at = parseInt(new Date().getTime()/1000);
|
594
|
+
$(opts.gauges).each(function(i,gauge){
|
595
|
+
$.ajax({
|
596
|
+
url: '/'+currentNamespace+'/gauge/'+gauge+'?at='+at,
|
597
|
+
success: function(_resp){
|
598
|
+
var resp = JSON.parse(_resp);
|
599
|
+
gauges_left -= 1;
|
600
|
+
for(_tk in resp){
|
601
|
+
gauge_values[gauge] = parseInt(resp[_tk]||0);
|
602
|
+
}
|
603
|
+
if(gauges_left==0){
|
604
|
+
redrawChart(first_time, gauge_values);
|
605
|
+
}
|
606
|
+
}
|
607
|
+
});
|
608
|
+
});
|
609
|
+
}
|
610
|
+
|
611
|
+
function redrawChart(first_time, gauge_values){
|
612
|
+
|
613
|
+
var series_data = [];
|
614
|
+
|
615
|
+
for(_gkey in gauge_values){
|
616
|
+
series_data.push([
|
617
|
+
opts.gauge_titles[_gkey],
|
618
|
+
gauge_values[_gkey]
|
619
|
+
]);
|
620
|
+
}
|
621
|
+
|
622
|
+
chart = new Highcharts.Chart({
|
623
|
+
chart: {
|
624
|
+
renderTo: 'container-'+widget_uid,
|
625
|
+
defaultSeriesType: 'pie',
|
626
|
+
height: 270,
|
627
|
+
spacingTop: 5,
|
628
|
+
spacingBottom: 30
|
629
|
+
},
|
630
|
+
credits: {
|
631
|
+
enabled: false
|
632
|
+
},
|
633
|
+
title: { text: '' },
|
634
|
+
legend: {
|
635
|
+
layout: 'horizontal',
|
636
|
+
align: 'top',
|
637
|
+
verticalAlign: 'top',
|
638
|
+
margin: 25,
|
639
|
+
borderWidth: 0
|
640
|
+
},
|
641
|
+
tooltip: {
|
642
|
+
formatter: function() {
|
643
|
+
return '<b>'+ this.point.name +'</b>: '+ this.y + ' (' + this.percentage.toFixed(1) + '%)';
|
644
|
+
}
|
645
|
+
},
|
646
|
+
plotOptions: {
|
647
|
+
pie: {
|
648
|
+
animation: first_time,
|
649
|
+
dataLabels: {
|
650
|
+
formatter: function() {
|
651
|
+
return '<b>'+ this.point.name +'</b><br />'+ this.percentage.toFixed(1) +' %';
|
652
|
+
}
|
653
|
+
}
|
654
|
+
}
|
655
|
+
},
|
656
|
+
series: [
|
657
|
+
{
|
658
|
+
name: opts.title,
|
659
|
+
data: series_data
|
660
|
+
}
|
661
|
+
]
|
662
|
+
});
|
663
|
+
|
664
|
+
//chart.redraw();
|
665
|
+
$(opts.elem).css('opacity', 1);
|
666
|
+
}
|
667
|
+
|
668
|
+
function drawLayout(){
|
669
|
+
$(opts.elem).append( $('<div></div>').attr('class', 'headbar small').append(
|
670
|
+
$('<span></span>').html(opts.title)
|
671
|
+
) ).append(
|
672
|
+
$('<div></div>').attr('id', 'container-'+widget_uid).css({
|
673
|
+
height: 270
|
674
|
+
})
|
675
|
+
);
|
676
|
+
}
|
677
|
+
|
678
|
+
drawLayout();
|
679
|
+
redraw(true);
|
680
|
+
|
681
|
+
if(opts.autoupdate){
|
682
|
+
var autoupdate_interval = window.setInterval(function(){
|
683
|
+
redraw(false, true);
|
684
|
+
}, opts.autoupdate*1000);
|
685
|
+
|
686
|
+
$('body').bind('fm_dashboard_close', function(){
|
687
|
+
window.clearInterval(autoupdate_interval);
|
688
|
+
});
|
689
|
+
}
|
690
|
+
|
691
|
+
}
|
692
|
+
|
693
|
+
return {
|
694
|
+
render: render
|
695
|
+
};
|
696
|
+
|
697
|
+
};
|
698
|
+
|
699
|
+
|
700
|
+
var sessionView = (function(){
|
701
|
+
|
702
|
+
var listElem = $('<ul class="session_list"></ul>');
|
703
|
+
var feedInnerElem = $('<ul class="feed_inner"></ul>');
|
704
|
+
var typeListElem = $('<ul class="event_type_list"></ul>');
|
705
|
+
var filterElem = $('<div class="events_sidebar"></div>').html(
|
706
|
+
$('<div class="headbar small"></div>').html('Event Types')
|
707
|
+
).append(typeListElem);
|
708
|
+
var feedElem = $('<div class="sessions_feed"></div>').html(
|
709
|
+
$('<div class="headbar small"></div>').html('Event Feed')
|
710
|
+
).append(feedInnerElem);
|
711
|
+
var sideElem = $('<div class="sessions_sidebar"></div>').html(
|
712
|
+
$('<div class="headbar small"></div>').html('Active Users')
|
713
|
+
).append(listElem);
|
714
|
+
|
715
|
+
var eventsPolledUntil = false;
|
716
|
+
var eventsFilter = [];
|
717
|
+
var sessionData = {};
|
718
|
+
var pollRunning = true;
|
719
|
+
|
720
|
+
function load(elem){
|
721
|
+
eventsPolledUntil = parseInt(new Date().getTime()/10000);
|
722
|
+
elem.html('')
|
723
|
+
.append(filterElem)
|
724
|
+
.append(feedElem)
|
725
|
+
.append(sideElem);
|
726
|
+
startPoll();
|
727
|
+
loadEventTypes();
|
728
|
+
};
|
729
|
+
|
730
|
+
function resize(_width, _height){
|
731
|
+
$('.sessions_feed').width(_width-452);
|
732
|
+
};
|
733
|
+
|
734
|
+
function startPoll(){
|
735
|
+
(doSessionPoll())();
|
736
|
+
(doEventsPoll())();
|
737
|
+
sessionView.session_poll = window.setInterval(doSessionPoll(), 1000);
|
738
|
+
};
|
739
|
+
|
740
|
+
function stopPoll(){
|
741
|
+
pollRunning = false;
|
742
|
+
window.clearInterval(sessionView.session_poll);
|
743
|
+
}
|
744
|
+
|
745
|
+
function doSessionPoll(){
|
746
|
+
return (function(){
|
747
|
+
$.ajax({
|
748
|
+
url: '/'+currentNamespace+'/sessions',
|
749
|
+
success: callbackSessionPoll()
|
750
|
+
});
|
751
|
+
});
|
752
|
+
};
|
753
|
+
|
754
|
+
function loadEventHistory(event_type){
|
755
|
+
feedInnerElem.html('');
|
756
|
+
$.ajax({
|
757
|
+
url: '/'+currentNamespace+'/events?type='+event_type,
|
758
|
+
success: function(_data, _status){
|
759
|
+
var data = JSON.parse(_data).events;
|
760
|
+
for(var n=data.length; n >= 0; n--){
|
761
|
+
if(data[n]){ renderEvent(data[n]); }
|
762
|
+
}
|
763
|
+
}
|
764
|
+
});
|
765
|
+
}
|
766
|
+
|
767
|
+
function callbackSessionPoll(){
|
768
|
+
return (function(_data, _status){
|
769
|
+
$.each(JSON.parse(_data).sessions, function(i,v){
|
770
|
+
updateSession(v);
|
771
|
+
});
|
772
|
+
sortSessions();
|
773
|
+
});
|
774
|
+
};
|
775
|
+
|
776
|
+
function loadEventTypes(){
|
777
|
+
$.ajax({
|
778
|
+
url: '/'+currentNamespace+'/event_types',
|
779
|
+
success: function(_data){
|
780
|
+
var data = JSON.parse(_data);
|
781
|
+
$(data.types).each(function(i,v){
|
782
|
+
if(v.slice(0,5)!='_set_'){ addEventType(v,v); }
|
783
|
+
});
|
784
|
+
}
|
785
|
+
});
|
786
|
+
};
|
787
|
+
|
788
|
+
function addEventType(type, display){
|
789
|
+
typeListElem.append(
|
790
|
+
$('<li class="event_type"></li>').append(
|
791
|
+
$('<span class="history"></span>').html('history')
|
792
|
+
.click(function(){
|
793
|
+
$('.event_type_list .event_type input').attr('checked', false);
|
794
|
+
$('input', $(this).parent()).attr('checked', true);
|
795
|
+
updateEventFilter(); loadEventHistory(type);
|
796
|
+
})
|
797
|
+
).append(
|
798
|
+
$('<input type="checkbox" />').attr('checked', true)
|
799
|
+
.click(function(){ updateEventFilter(); })
|
800
|
+
).append(
|
801
|
+
$('<span></span>').html(display)
|
802
|
+
).attr('rel', type)
|
803
|
+
);
|
804
|
+
}
|
805
|
+
|
806
|
+
function updateEventFilter(){
|
807
|
+
var _unchecked_types = [];
|
808
|
+
$('ul.event_type_list li.event_type').each(function(i,v){
|
809
|
+
if(!$('input', v).attr('checked')){
|
810
|
+
_unchecked_types.push($(v).attr('rel'));
|
811
|
+
}
|
812
|
+
});
|
813
|
+
eventsFilter = _unchecked_types;
|
814
|
+
}
|
815
|
+
|
816
|
+
function doEventsPoll(){
|
817
|
+
return (function(){
|
818
|
+
$.ajax({
|
819
|
+
url: '/'+currentNamespace+'/events?since='+eventsPolledUntil,
|
820
|
+
success: callbackEventsPoll()
|
821
|
+
});
|
822
|
+
});
|
823
|
+
};
|
824
|
+
|
825
|
+
function callbackEventsPoll(){
|
826
|
+
return (function(_data, _status){
|
827
|
+
var data = JSON.parse(_data)
|
828
|
+
var events = data.events;
|
829
|
+
var timout = 1000;
|
830
|
+
var maxevents = 200;
|
831
|
+
if(events.length > 0){
|
832
|
+
timeout = 200;
|
833
|
+
eventsPolledUntil = parseInt(events[0]._time)-1;
|
834
|
+
}
|
835
|
+
for(var n=events.length-1; n >= 0; n--){
|
836
|
+
var v = events[n];
|
837
|
+
if(eventsFilter.indexOf(v._type) == -1){
|
838
|
+
if(parseInt(v._time)<=eventsPolledUntil){
|
839
|
+
renderEvent(v);
|
840
|
+
}
|
841
|
+
}
|
842
|
+
};
|
843
|
+
var elems = $("p", feedInnerElem);
|
844
|
+
for(var n=maxevents; n < elems.length; n++){
|
845
|
+
$(elems[n]).remove();
|
846
|
+
}
|
847
|
+
if(pollRunning){
|
848
|
+
window.setTimeout(doEventsPoll(), timout);
|
849
|
+
}
|
850
|
+
});
|
851
|
+
};
|
852
|
+
|
853
|
+
function updateSession(session_data){
|
854
|
+
sessionData[session_data.session_key] = session_data;
|
855
|
+
renderSession(session_data);
|
856
|
+
}
|
857
|
+
|
858
|
+
function sortSessions(){
|
859
|
+
console.log("fixme: sort and splice to 100");
|
860
|
+
}
|
861
|
+
|
862
|
+
function renderSession(session_data){
|
863
|
+
|
864
|
+
var session_name = session_data["_name"];
|
865
|
+
var session_time = formatTimeSince(session_data["_updated_at"]);
|
866
|
+
var session_elem = $('li[data-session='+session_data["session_key"]+']:first');
|
867
|
+
|
868
|
+
if(session_elem.length>0){
|
869
|
+
|
870
|
+
if(session_data["_picture"] && (session_data["_picture"].length > 1)){
|
871
|
+
$('.picture img', session_elem).attr('src', session_data["_picture"])
|
872
|
+
}
|
873
|
+
|
874
|
+
if(session_name){
|
875
|
+
$('.name', session_elem).html(session_name);
|
876
|
+
}
|
877
|
+
|
878
|
+
$('.time', session_elem).html(session_time);
|
879
|
+
|
880
|
+
} else {
|
881
|
+
|
882
|
+
var session_picture = $('<img width="18" />');
|
883
|
+
|
884
|
+
if(!session_name){
|
885
|
+
session_name = session_data["session_key"].substr(0,15)
|
886
|
+
};
|
887
|
+
|
888
|
+
if(session_data["_picture"]){
|
889
|
+
session_picture.attr('src', session_data["_picture"]);
|
890
|
+
};
|
891
|
+
|
892
|
+
listElem.append(
|
893
|
+
$('<li class="session"></li>').append(
|
894
|
+
$('<div class="picture"></div>').html(session_picture)
|
895
|
+
).append(
|
896
|
+
$('<span class="name"></span>').html(session_name)
|
897
|
+
).append(
|
898
|
+
$('<span class="time"></span>').html(session_time)
|
899
|
+
).attr('data-session', session_data["session_key"])
|
900
|
+
);
|
901
|
+
|
902
|
+
}
|
903
|
+
};
|
904
|
+
|
905
|
+
function renderEvent(event_data){
|
906
|
+
var event_time = $('<span class="time"></span>');
|
907
|
+
var event_message = $('<span class="message"></span>');
|
908
|
+
var event_props = $('<span class="properties"></span>');
|
909
|
+
var event_picture = $('<div class="picture"></picture>');
|
910
|
+
|
911
|
+
var event_type = event_data._type;
|
912
|
+
|
913
|
+
if(!event_type){ return true; }
|
914
|
+
|
915
|
+
if(event_data._message){
|
916
|
+
event_message.html(event_data._message);
|
917
|
+
} else if(event_type=="_pageview"){
|
918
|
+
event_message.html("Pageview: " + event_data.url);
|
919
|
+
} else if(event_type.substr(0,5) == '_set_'){
|
920
|
+
return true; /* dont render */
|
921
|
+
} else {
|
922
|
+
event_message.html(event_type);
|
923
|
+
}
|
924
|
+
|
925
|
+
event_time.html(formatTimeOfDay(event_data._time));
|
926
|
+
|
927
|
+
if(event_data._session_key && event_data._session_key.length > 0){
|
928
|
+
if(session_data=sessionData[event_data._session_key]){
|
929
|
+
if(session_data._name){
|
930
|
+
event_props.append(
|
931
|
+
$('<strong></strong>').html(session_data._name)
|
932
|
+
);
|
933
|
+
}
|
934
|
+
if(session_data._picture){
|
935
|
+
event_picture.append(
|
936
|
+
$('<img width="40" />').attr('src', session_data._picture)
|
937
|
+
)
|
938
|
+
}
|
939
|
+
}
|
940
|
+
}
|
941
|
+
|
942
|
+
feedInnerElem.prepend(
|
943
|
+
$('<li class="feed_event"></li>')
|
944
|
+
.append(event_time)
|
945
|
+
.append(event_picture)
|
946
|
+
.append(event_message)
|
947
|
+
.append(event_props)
|
948
|
+
);
|
949
|
+
}
|
950
|
+
|
951
|
+
function close(){
|
952
|
+
stopPoll();
|
953
|
+
};
|
954
|
+
|
955
|
+
return {
|
956
|
+
load: load,
|
957
|
+
resize: resize,
|
958
|
+
close: close
|
959
|
+
};
|
960
|
+
|
961
|
+
});
|
962
|
+
|
963
|
+
|
964
|
+
var dashboardView = (function(dashboard_name){
|
965
|
+
|
966
|
+
var widgets = [];
|
967
|
+
var viewport = null;
|
968
|
+
|
969
|
+
function load(_viewport){
|
970
|
+
viewport = _viewport.html('');
|
971
|
+
$.ajax({
|
972
|
+
url: '/'+currentNamespace+'/dashboard/'+dashboard_name,
|
973
|
+
success: function(resp, status){
|
974
|
+
var conf = JSON.parse(resp);
|
975
|
+
renderWidgets(conf.widgets);
|
976
|
+
}
|
977
|
+
});
|
978
|
+
};
|
979
|
+
|
980
|
+
function renderWidgets(_widgets){
|
981
|
+
for(wkey in _widgets){
|
982
|
+
var widget = _widgets[wkey];
|
983
|
+
widget["elem"] = $('<div class="widget"></div>');
|
984
|
+
widgets[wkey] = widget;
|
985
|
+
viewport.append(widget.elem);
|
986
|
+
resizeWidget(wkey);
|
987
|
+
renderWidget(wkey);
|
988
|
+
};
|
989
|
+
resize();
|
990
|
+
};
|
991
|
+
|
992
|
+
function renderWidget(wkey){
|
993
|
+
var widget = widgets[wkey];
|
994
|
+
/* argh... */
|
995
|
+
if(widget.klass=='TimelineWidget'){ timelineWidget().render(widget); }
|
996
|
+
if(widget.klass=='BarsWidget'){ barsWidget().render(widget); }
|
997
|
+
if(widget.klass=='NumbersWidget'){ numbersWidget().render(widget); }
|
998
|
+
if(widget.klass=='ToplistWidget'){ toplistWidget().render(widget); }
|
999
|
+
if(widget.klass=='PieWidget'){ pieWidget().render(widget); }
|
1000
|
+
};
|
1001
|
+
|
1002
|
+
function resizeWidget(wkey){
|
1003
|
+
var widget = widgets[wkey];
|
1004
|
+
var wwperc = widgets[wkey].width;
|
1005
|
+
if(!wwperc){ wwperc = 100; }
|
1006
|
+
var wwidth = viewport.width() * (wwperc/100.0);
|
1007
|
+
if(wwperc==100){
|
1008
|
+
widgets[wkey].elem.addClass('full_width');
|
1009
|
+
} else { wwidth -= 1; }
|
1010
|
+
widget.elem.width(wwidth);
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
function resize(){
|
1014
|
+
for(wkey in widgets){
|
1015
|
+
resizeWidget(wkey);
|
1016
|
+
};
|
1017
|
+
};
|
1018
|
+
|
1019
|
+
function close(){
|
1020
|
+
$('body').trigger('fm_dashboard_close');
|
1021
|
+
};
|
1022
|
+
|
1023
|
+
return {
|
1024
|
+
load: load,
|
1025
|
+
resize: resize,
|
1026
|
+
close: close
|
1027
|
+
};
|
1028
|
+
|
1029
|
+
});
|
1030
|
+
|
1031
|
+
|
1032
|
+
function renderDashboard(_dash){
|
1033
|
+
loadView(dashboardView(_dash));
|
1034
|
+
};
|
1035
|
+
|
1036
|
+
function renderSessionView(){
|
1037
|
+
loadView(sessionView());
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
function loadView(_view){
|
1041
|
+
if(currentView){ currentView.close(); }
|
1042
|
+
canvasElem.html('loading!');
|
1043
|
+
currentView = _view;
|
1044
|
+
currentView.load(canvasElem);
|
1045
|
+
resizeView();
|
1046
|
+
};
|
1047
|
+
|
1048
|
+
function resizeView(){
|
1049
|
+
currentView.resize(
|
1050
|
+
canvasElem.innerWidth(),
|
1051
|
+
canvasElem.innerHeight()
|
1052
|
+
);
|
1053
|
+
};
|
1054
|
+
|
1055
|
+
function init(_namespace, _canvasElem){
|
1056
|
+
canvasElem = _canvasElem;
|
1057
|
+
currentNamespace = _namespace;
|
1058
|
+
loadView(sessionView());
|
1059
|
+
};
|
1060
|
+
|
1061
|
+
return {
|
1062
|
+
p: '/fnordmetric/',
|
1063
|
+
renderDashboard: renderDashboard,
|
1064
|
+
renderSessionView: renderSessionView,
|
1065
|
+
resizeView: resizeView,
|
1066
|
+
init: init
|
1067
|
+
};
|
1068
|
+
|
1069
|
+
})();
|