##// END OF EJS Templates
Some fixes to summary, and total rewrite of summary graphs implemented more interactive graph....
marcink -
r487:b12ea84f celery
parent child Browse files
Show More
@@ -14,13 +14,16 b' class ResultWrapper(object):'
14 def result(self):
14 def result(self):
15 return self.task
15 return self.task
16
16
17 def run_task(task,*args,**kwargs):
17 def run_task(task, *args, **kwargs):
18 try:
18 try:
19 t = task.delay(*args,**kwargs)
19 t = task.delay(*args, **kwargs)
20 log.info('running task %s',t.task_id)
20 log.info('running task %s', t.task_id)
21 return t
21 return t
22 except:
22 except Exception, e:
23 log.error(traceback.format_exc())
23 if e.errno == 111:
24 log.debug('Unnable to connect. Sync execution')
25 else:
26 log.error(traceback.format_exc())
24 #pure sync version
27 #pure sync version
25 return ResultWrapper(task(*args,**kwargs))
28 return ResultWrapper(task(*args, **kwargs))
26 No newline at end of file
29
@@ -7,8 +7,9 b' from pylons_app.lib.celerylib import run'
7 from pylons_app.lib.helpers import person
7 from pylons_app.lib.helpers import person
8 from pylons_app.lib.smtp_mailer import SmtpMailer
8 from pylons_app.lib.smtp_mailer import SmtpMailer
9 from pylons_app.lib.utils import OrderedDict
9 from pylons_app.lib.utils import OrderedDict
10 from operator import itemgetter
11 from vcs.backends.hg import MercurialRepository
10 from time import mktime
12 from time import mktime
11 from vcs.backends.hg import MercurialRepository
12 import calendar
13 import calendar
13 import traceback
14 import traceback
14 import json
15 import json
@@ -98,13 +99,14 b' def get_commits_stats(repo):'
98 d, 0, 0, 0, 0, 0, 0,))
99 d, 0, 0, 0, 0, 0, 0,))
99
100
100 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
101 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
101
102 skip_date_limit = True
103
102 def author_key_cleaner(k):
104 def author_key_cleaner(k):
103 k = person(k)
105 k = person(k)
104 k = k.replace('"', "") #for js data compatibilty
106 k = k.replace('"', "") #for js data compatibilty
105 return k
107 return k
106
108
107 for cs in repo[:1000]:#added limit 200 until fix #29 is made
109 for cs in repo[:200]:#added limit 200 until fix #29 is made
108 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
110 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
109 cs.date.timetuple()[2])
111 cs.date.timetuple()[2])
110 timetupple = [int(x) for x in k.split('-')]
112 timetupple = [int(x) for x in k.split('-')]
@@ -119,7 +121,7 b' def get_commits_stats(repo):'
119
121
120 else:
122 else:
121 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
123 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
122 if k >= ts_min_y and k <= ts_max_y:
124 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
123 aggregate[author_key_cleaner(cs.author)][k] = {}
125 aggregate[author_key_cleaner(cs.author)][k] = {}
124 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
126 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
125 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
127 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
@@ -127,7 +129,7 b' def get_commits_stats(repo):'
127 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
129 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
128
130
129 else:
131 else:
130 if k >= ts_min_y and k <= ts_max_y:
132 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
131 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
133 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
132 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
134 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
133 aggregate[author_key_cleaner(cs.author)][k] = {}
135 aggregate[author_key_cleaner(cs.author)][k] = {}
@@ -145,15 +147,19 b' def get_commits_stats(repo):'
145 overview_data = []
147 overview_data = []
146 for k, v in overview_aggregate.items():
148 for k, v in overview_aggregate.items():
147 overview_data.append([k, v])
149 overview_data.append([k, v])
150 overview_data = sorted(overview_data, key=itemgetter(0))
148 data = {}
151 data = {}
149 for author in aggregate:
152 for author in aggregate:
150 data[author] = {"label":author,
153 commit_data = sorted([{"time":x,
151 "data":[{"time":x,
152 "commits":aggregate[author][x]['commits'],
154 "commits":aggregate[author][x]['commits'],
153 "added":aggregate[author][x]['added'],
155 "added":aggregate[author][x]['added'],
154 "changed":aggregate[author][x]['changed'],
156 "changed":aggregate[author][x]['changed'],
155 "removed":aggregate[author][x]['removed'],
157 "removed":aggregate[author][x]['removed'],
156 } for x in aggregate[author]],
158 } for x in aggregate[author]],
159 key=itemgetter('time'))
160
161 data[author] = {"label":author,
162 "data":commit_data,
157 "schema":["commits"]
163 "schema":["commits"]
158 }
164 }
159
165
@@ -76,7 +76,9 b' E.onDOMReady(function(e){'
76 <label>${_('Last change')}:</label>
76 <label>${_('Last change')}:</label>
77 </div>
77 </div>
78 <div class="input-short">
78 <div class="input-short">
79 ${h.age(c.repo_info.last_change)} - ${h.rfc822date(c.repo_info.last_change)}
79 ${h.age(c.repo_info.last_change)} - ${h.rfc822date(c.repo_info.last_change)}
80 ${_('by')} ${c.repo_info.get_changeset('tip').author}
81
80 </div>
82 </div>
81 </div>
83 </div>
82
84
@@ -121,7 +123,7 b' E.onDOMReady(function(e){'
121 <div class="box box-right" style="min-height:455px">
123 <div class="box box-right" style="min-height:455px">
122 <!-- box / title -->
124 <!-- box / title -->
123 <div class="title">
125 <div class="title">
124 <h5>${_('Last month commit activity')}</h5>
126 <h5>${_('Commit activity')}</h5>
125 </div>
127 </div>
126
128
127 <div class="table">
129 <div class="table">
@@ -136,191 +138,341 b' E.onDOMReady(function(e){'
136 </div>
138 </div>
137 </div>
139 </div>
138 <script type="text/javascript">
140 <script type="text/javascript">
139
141 /**
140 (function () {
142 * Plots summary graph
141 var datasets = ${c.commit_data|n};
143 *
142 var overview_data = ${c.overview_data|n};
144 * @class SummaryPlot
143
145 * @param {from} initial from for detailed graph
144 var i = 0;
146 * @param {to} initial to for detailed graph
147 * @param {dataset}
148 * @param {overview_dataset}
149 */
150 function SummaryPlot(from,to,dataset,overview_dataset) {
151 var initial_ranges = {
152 "xaxis":{
153 "from":from,
154 "to":to,
155 },
156 };
157 var dataset = dataset;
158 var overview_dataset = [overview_dataset];
145 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
159 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
146 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
160 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
147 for(var key in datasets) {
161 var plotContainer = YAHOO.util.Dom.get('commit_history');
148 datasets[key].color = i;
162 var overviewContainer = YAHOO.util.Dom.get('overview');
149 i++;
163
150 choiceContainerTable.innerHTML += '<tr><td>'+
164 var plot_options = {
151 '<input type="checkbox" name="' + key +'" checked="checked" />'
165 bars: {show:true,align:'center',lineWidth:4},
152 +datasets[key].label+
166 legend: {show:true, container:"legend_container"},
153 '</td></tr>';
167 points: {show:true,radius:0,fill:false},
168 yaxis: {tickDecimals:0,},
169 xaxis: {
170 mode: "time",
171 timeformat: "%d/%m",
172 min:from,
173 max:to,
174 },
175 grid: {
176 hoverable: true,
177 clickable: true,
178 autoHighlight:true,
179 color: "#999"
180 },
181 //selection: {mode: "x"}
154 };
182 };
155
183 var overview_options = {
156 function plotAccordingToChoices() {
184 legend:{show:false},
157 var data = [];
185 bars: {show:true,barWidth: 2,},
158
186 shadowSize: 0,
159 var inputs = choiceContainer.getElementsByTagName("input");
187 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
160 for(var i=0; i<inputs.length; i++) {
188 yaxis: {ticks: 3, min: 0,},
161 var key = inputs[i].name;
189 grid: {color: "#999",},
162 if (key && datasets[key]){
190 selection: {mode: "x"}
163 if(!inputs[i].checked){
191 };
164 data.push({label:key,data:[[0,1],]});
165 }
166 else{
167 data.push(datasets[key]);
168 }
169 }
170 };
171
172 if (data.length > 0){
173 var options = {
174 bars: {show:true,align:'center',lineWidth:4},
175 legend: {show:true, container:"legend_container"},
176 points: {show:true,radius:0,fill:false},
177 yaxis: {tickDecimals:0,},
178 xaxis: {mode: "time",
179 timeformat: "%d/%m",
180 min:${c.ts_min},
181 max:${c.ts_max},
182
183 },
184 grid: {hoverable: true,
185 clickable: true,
186 autoHighlight:true,
187 color: "#999"},
188 selection: {mode: "x"}
189 };
190
192
191 //main plot
193 /**
192 var plot = YAHOO.widget.Flot("commit_history",data,options);
194 *get dummy data needed in few places
193
195 */
194 //overview
196 function getDummyData(label){
195 var overview = YAHOO.widget.Flot("overview", [overview_data], {
197 return {"label":label,
196 legend:{show:false},
198 "data":[{"time":0,
197 bars: {show:true,
199 "commits":0,
198 barWidth: 2,
200 "added":0,
199 },
201 "changed":0,
200 shadowSize: 0,
202 "removed":0,
201 xaxis: {mode: "time",
203 }],
202 timeformat: "%d/%m/%y",
204 "schema":["commits"],
203 },
205 "color":'#ffffff',
204 yaxis: {ticks: 3, min: 0,},
206 }
205 grid: {color: "#999",},
207 }
206 selection: {mode: "x"}
208
207 });
209 /**
210 * generate checkboxes accordindly to data
211 * @param keys
212 * @returns
213 */
214 function generateCheckboxes(data) {
215 //append checkboxes
216 var i = 0;
217 choiceContainerTable.innerHTML = '';
218 for(var pos in data) {
219
220 data[pos].color = i;
221 i++;
222 if(data[pos].label != ''){
223 choiceContainerTable.innerHTML += '<tr><td>'+
224 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
225 +data[pos].label+
226 '</td></tr>';
227 }
228 }
229 }
230
231 /**
232 * ToolTip show
233 */
234 function showTooltip(x, y, contents) {
235 var div=document.getElementById('tooltip');
236 if(!div) {
237 div = document.createElement('div');
238 div.id="tooltip";
239 div.style.position="absolute";
240 div.style.border='1px solid #fdd';
241 div.style.padding='2px';
242 div.style.backgroundColor='#fee';
243 document.body.appendChild(div);
244 }
245 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
246 div.innerHTML = contents;
247 div.style.top=(y + 5) + "px";
248 div.style.left=(x + 5) + "px";
208
249
209 var ranges = {"xaxis":{"from":${c.ts_min},
250 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
210 "to":${c.ts_max},},}
251 anim.animate();
211 overview.setSelection(ranges);
252 }
212
253
213 function showTooltip(x, y, contents) {
254 /**
214 var div=document.getElementById('tooltip');
255 * This function will detect if selected period has some changesets for this user
215 if(!div) {
256 if it does this data is then pushed for displaying
216 div = document.createElement('div');
257 Additionally it will only display users that are selected by the checkbox
217 div.id="tooltip";
258 */
218 div.style.position="absolute";
259 function getDataAccordingToRanges(ranges) {
219 div.style.border='1px solid #fdd';
260
220 div.style.padding='2px';
261 var data = [];
221 div.style.backgroundColor='#fee';
262 var keys = [];
222 document.body.appendChild(div);
263 for(var key in dataset){
223 }
264 var push = false;
224 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
265 //method1 slow !!
225 div.innerHTML = contents;
266 ///*
226 div.style.top=(y + 5) + "px";
267 for(var ds in dataset[key].data){
227 div.style.left=(x + 5) + "px";
268 commit_data = dataset[key].data[ds];
228
269 //console.log(key);
229 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
270 //console.log(new Date(commit_data.time*1000));
230 anim.animate();
271 //console.log(new Date(ranges.xaxis.from*1000));
272 //console.log(new Date(ranges.xaxis.to*1000));
273 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
274 push = true;
275 break;
276 }
231 }
277 }
278 //*/
279 /*//method2 sorted commit data !!!
280 var first_commit = dataset[key].data[0].time;
281 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
232
282
233 var previousPoint = null;
283 console.log(first_commit);
284 console.log(last_commit);
285
286 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
287 push = true;
288 }
289 */
290 if(push){
291 data.push(dataset[key]);
292 }
293 }
294 if(data.length >= 1){
295 return data;
296 }
297 else{
298 //just return dummy data for graph to plot itself
299 return [getDummyData('')];
300 }
301
302 }
303
304 /**
305 * redraw using new checkbox data
306 */
307 function plotchoiced(e,args){
308 var cur_data = args[0];
309 var cur_ranges = args[1];
310
311 var new_data = [];
312 var inputs = choiceContainer.getElementsByTagName("input");
234
313
235 function plothover(o) {
314 //show only checked labels
236 var pos = o.pos;
315 for(var i=0; i<inputs.length; i++) {
237 var item = o.item;
316 var checkbox_key = inputs[i].name;
238
317
239 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
318 if(inputs[i].checked){
240 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
319 for(var d in cur_data){
241 if (item) {
320 if(cur_data[d].label == checkbox_key){
242 if (previousPoint != item.datapoint) {
321 new_data.push(cur_data[d]);
243 previousPoint = item.datapoint;
322 }
244
323 }
245 var tooltip = YAHOO.util.Dom.get("tooltip");
324 }
246 if(tooltip) {
325 else{
247 tooltip.parentNode.removeChild(tooltip);
326 //push dummy data to not hide the label
248 }
327 new_data.push(getDummyData(checkbox_key));
249 var x = item.datapoint.x.toFixed(2);
328 }
250 var y = item.datapoint.y.toFixed(2);
329 }
251
330
252 if (!item.series.label){
331 var new_options = YAHOO.lang.merge(plot_options, {
253 item.series.label = 'commits';
332 xaxis: {
254 }
333 min: cur_ranges.xaxis.from,
255 var d = new Date(x*1000);
334 max: cur_ranges.xaxis.to,
256 var fd = d.toDateString()
335 mode:"time",
257 var nr_commits = parseInt(y);
336 timeformat: "%d/%m",
258
337 }
259 var cur_data = datasets[item.series.label].data[item.dataIndex];
338 });
260 var added = cur_data.added;
339 if (!new_data){
261 var changed = cur_data.changed;
340 new_data = [[0,1]];
262 var removed = cur_data.removed;
341 }
263
342 // do the zooming
264 var nr_commits_suffix = " ${_('commits')} ";
343 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
265 var added_suffix = " ${_('files added')} ";
344
266 var changed_suffix = " ${_('files changed')} ";
345 plot.subscribe("plotselected", plotselected);
267 var removed_suffix = " ${_('files removed')} ";
346
347 //resubscribe plothover
348 plot.subscribe("plothover", plothover);
349
350 // don't fire event on the overview to prevent eternal loop
351 overview.setSelection(cur_ranges, true);
352
353 }
354
355 /**
356 * plot only selected items from overview
357 * @param ranges
358 * @returns
359 */
360 function plotselected(ranges,cur_data) {
361 //updates the data for new plot
362 data = getDataAccordingToRanges(ranges);
363 generateCheckboxes(data);
364
365 var new_options = YAHOO.lang.merge(plot_options, {
366 xaxis: {
367 min: ranges.xaxis.from,
368 max: ranges.xaxis.to,
369 mode:"time",
370 timeformat: "%d/%m",
371 }
372 });
373 // do the zooming
374 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
375
376 plot.subscribe("plotselected", plotselected);
377
378 //resubscribe plothover
379 plot.subscribe("plothover", plothover);
380
381 // don't fire event on the overview to prevent eternal loop
382 overview.setSelection(ranges, true);
383
384 //resubscribe choiced
385 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
386 }
387
388 var previousPoint = null;
268
389
269
390 function plothover(o) {
270 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
391 var pos = o.pos;
271 if(added==1){added_suffix=" ${_('file added')} ";}
392 var item = o.item;
272 if(changed==1){changed_suffix=" ${_('file changed')} ";}
393
273 if(removed==1){removed_suffix=" ${_('file removed')} ";}
394 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
274
395 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
275 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
396 if (item) {
276 +'<br/>'+
397 if (previousPoint != item.datapoint) {
277 nr_commits + nr_commits_suffix+'<br/>'+
398 previousPoint = item.datapoint;
278 added + added_suffix +'<br/>'+
399
279 changed + changed_suffix + '<br/>'+
400 var tooltip = YAHOO.util.Dom.get("tooltip");
280 removed + removed_suffix + '<br/>');
401 if(tooltip) {
281 }
402 tooltip.parentNode.removeChild(tooltip);
282 }
403 }
283 else {
404 var x = item.datapoint.x.toFixed(2);
284 var tooltip = YAHOO.util.Dom.get("tooltip");
405 var y = item.datapoint.y.toFixed(2);
285
406
286 if(tooltip) {
407 if (!item.series.label){
287 tooltip.parentNode.removeChild(tooltip);
408 item.series.label = 'commits';
288 }
289 previousPoint = null;
290 }
409 }
291 }
410 var d = new Date(x*1000);
292
411 var fd = d.toDateString()
293 plot.subscribe("plothover", plothover);
412 var nr_commits = parseInt(y);
294
413
295 function plotselected(ranges) {
414 var cur_data = dataset[item.series.label].data[item.dataIndex];
296 // do the zooming
415 var added = cur_data.added;
297 plot = YAHOO.widget.Flot("commit_history", data,
416 var changed = cur_data.changed;
298 YAHOO.lang.merge(options, {
417 var removed = cur_data.removed;
299 xaxis: { min: ranges.xaxis.from,
418
300 max: ranges.xaxis.to,
419 var nr_commits_suffix = " ${_('commits')} ";
301 mode:"time",
420 var added_suffix = " ${_('files added')} ";
302 timeformat: "%d/%m",
421 var changed_suffix = " ${_('files changed')} ";
303 }
422 var removed_suffix = " ${_('files removed')} ";
304 }));
305 plot.subscribe("plotselected", plotselected);
306 plot.subscribe("plothover", plothover);
307
423
308 // don't fire event on the overview to prevent eternal loop
424
309 overview.setSelection(ranges, true);
425 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
310 }
426 if(added==1){added_suffix=" ${_('file added')} ";}
311 plot.subscribe("plotselected", plotselected);
427 if(changed==1){changed_suffix=" ${_('file changed')} ";}
312
428 if(removed==1){removed_suffix=" ${_('file removed')} ";}
313 overview.subscribe("plotselected", function (ranges) {
429
314 plot.setSelection(ranges);
430 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
315 });
431 +'<br/>'+
316 }
432 nr_commits + nr_commits_suffix+'<br/>'+
433 added + added_suffix +'<br/>'+
434 changed + changed_suffix + '<br/>'+
435 removed + removed_suffix + '<br/>');
436 }
437 }
438 else {
439 var tooltip = YAHOO.util.Dom.get("tooltip");
440
441 if(tooltip) {
442 tooltip.parentNode.removeChild(tooltip);
443 }
444 previousPoint = null;
445 }
317 }
446 }
318
447
319 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotAccordingToChoices);
448 /**
449 * MAIN EXECUTION
450 */
451
452 var data = getDataAccordingToRanges(initial_ranges);
453 generateCheckboxes(data);
454
455 //main plot
456 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
457
458 //overview
459 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
460
461 //show initial selection on overview
462 overview.setSelection(initial_ranges);
463
464 plot.subscribe("plotselected", plotselected);
465
466 overview.subscribe("plotselected", function (ranges) {
467 plot.setSelection(ranges);
468 });
469
470 plot.subscribe("plothover", plothover);
320
471
321 plotAccordingToChoices();
472 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
322 })();
473 }
323 </script>
474 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
475 </script>
324
476
325 </div>
477 </div>
326 </div>
478 </div>
General Comments 0
You need to be logged in to leave comments. Login now