##// END OF EJS Templates
rewrote graph plotting, added zooming and json dump insted of stupid string formating.
marcink -
r486:5c376ac2 celery
parent child Browse files
Show More
@@ -22,7 +22,7 b' Created on April 18, 2010'
22 22 summary controller for pylons
23 23 @author: marcink
24 24 """
25 from pylons import tmpl_context as c, request,url
25 from pylons import tmpl_context as c, request, url
26 26 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 27 from pylons_app.lib.base import BaseController, render
28 28 from pylons_app.lib.utils import OrderedDict
@@ -61,10 +61,11 b' class SummaryController(BaseController):'
61 61 for name, hash in c.repo_info.branches.items()[:10]:
62 62 c.repo_branches[name] = c.repo_info.get_changeset(hash)
63 63
64 task = run_task(get_commits_stats,c.repo_info.name)
64 task = run_task(get_commits_stats, c.repo_info.name)
65 65 c.ts_min = task.result[0]
66 66 c.ts_max = task.result[1]
67 67 c.commit_data = task.result[2]
68 c.overview_data = task.result[3]
68 69
69 70 return render('summary/summary.html')
70 71
@@ -11,6 +11,7 b' from time import mktime'
11 11 from vcs.backends.hg import MercurialRepository
12 12 import calendar
13 13 import traceback
14 import json
14 15
15 16 __all__ = ['whoosh_index', 'get_commits_stats',
16 17 'reset_user_password', 'send_email']
@@ -84,21 +85,26 b' def whoosh_index(repo_location, full_ind'
84 85 def get_commits_stats(repo):
85 86 log = get_commits_stats.get_logger()
86 87 aggregate = OrderedDict()
88 overview_aggregate = OrderedDict()
87 89 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
88 90 repo = MercurialRepository(repos_path + repo)
89 91 #graph range
90 92 td = datetime.today() + timedelta(days=1)
91 93 y, m, d = td.year, td.month, td.day
92 ts_min = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
94
95 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
93 96 d, 0, 0, 0, 0, 0, 0,))
94 ts_max = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
97 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
98 d, 0, 0, 0, 0, 0, 0,))
95 99
100 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
101
96 102 def author_key_cleaner(k):
97 103 k = person(k)
98 k = k.replace('"', "'") #for js data compatibilty
104 k = k.replace('"', "") #for js data compatibilty
99 105 return k
100 106
101 for cs in repo[:200]:#added limit 200 until fix #29 is made
107 for cs in repo[:1000]:#added limit 200 until fix #29 is made
102 108 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
103 109 cs.date.timetuple()[2])
104 110 timetupple = [int(x) for x in k.split('-')]
@@ -113,7 +119,7 b' def get_commits_stats(repo):'
113 119
114 120 else:
115 121 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
116 if k >= ts_min and k <= ts_max:
122 if k >= ts_min_y and k <= ts_max_y:
117 123 aggregate[author_key_cleaner(cs.author)][k] = {}
118 124 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
119 125 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
@@ -121,7 +127,7 b' def get_commits_stats(repo):'
121 127 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
122 128
123 129 else:
124 if k >= ts_min and k <= ts_max:
130 if k >= ts_min_y and k <= ts_max_y:
125 131 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
126 132 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
127 133 aggregate[author_key_cleaner(cs.author)][k] = {}
@@ -130,25 +136,35 b' def get_commits_stats(repo):'
130 136 aggregate[author_key_cleaner(cs.author)][k]["changed"] = len(cs.changed)
131 137 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
132 138
133 d = ''
134 tmpl0 = u""""%s":%s"""
135 tmpl1 = u"""{label:"%s",data:%s,schema:["commits"]},"""
136 for author in aggregate:
137 139
138 d += tmpl0 % (author,
139 tmpl1 \
140 % (author,
141 [{"time":x,
142 "commits":aggregate[author][x]['commits'],
143 "added":aggregate[author][x]['added'],
144 "changed":aggregate[author][x]['changed'],
145 "removed":aggregate[author][x]['removed'],
146 } for x in aggregate[author]]))
147 if d == '':
148 d = '"%s":{label:"%s",data:[[0,1],]}' \
149 % (author_key_cleaner(repo.contact),
150 author_key_cleaner(repo.contact))
151 return (ts_min, ts_max, d)
140 if overview_aggregate.has_key(k):
141 overview_aggregate[k] += 1
142 else:
143 overview_aggregate[k] = 1
144
145 overview_data = []
146 for k, v in overview_aggregate.items():
147 overview_data.append([k, v])
148 data = {}
149 for author in aggregate:
150 data[author] = {"label":author,
151 "data":[{"time":x,
152 "commits":aggregate[author][x]['commits'],
153 "added":aggregate[author][x]['added'],
154 "changed":aggregate[author][x]['changed'],
155 "removed":aggregate[author][x]['removed'],
156 } for x in aggregate[author]],
157 "schema":["commits"]
158 }
159
160 if not data:
161 data[author_key_cleaner(repo.contact)] = {
162 "label":author_key_cleaner(repo.contact),
163 "data":[0, 1],
164 "schema":["commits"],
165 }
166
167 return (ts_min_m, ts_max_y, json.dumps(data), json.dumps(overview_data))
152 168
153 169 @task
154 170 def reset_user_password(user_email):
@@ -157,7 +173,6 b' def reset_user_password(user_email):'
157 173 from pylons_app.model.db import User
158 174
159 175 try:
160
161 176 try:
162 177 sa = get_session()
163 178 user = sa.query(User).filter(User.email == user_email).scalar()
@@ -126,7 +126,10 b' E.onDOMReady(function(e){'
126 126
127 127 <div class="table">
128 128 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
129 <div id="legend_data" style="clear:both;margin-top:10px">
129 <div style="clear: both;height: 10px"></div>
130 <div id="overview" style="width:560px;height:100px;float:left"></div>
131
132 <div id="legend_data" style="clear:both;margin-top:10px;">
130 133 <div id="legend_container"></div>
131 134 <div id="legend_choices">
132 135 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
@@ -135,7 +138,9 b' E.onDOMReady(function(e){'
135 138 <script type="text/javascript">
136 139
137 140 (function () {
138 var datasets = {${c.commit_data|n}};
141 var datasets = ${c.commit_data|n};
142 var overview_data = ${c.overview_data|n};
143
139 144 var i = 0;
140 145 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
141 146 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
@@ -147,8 +152,7 b' E.onDOMReady(function(e){'
147 152 +datasets[key].label+
148 153 '</td></tr>';
149 154 };
150
151
155
152 156 function plotAccordingToChoices() {
153 157 var data = [];
154 158
@@ -162,23 +166,50 b' E.onDOMReady(function(e){'
162 166 else{
163 167 data.push(datasets[key]);
164 168 }
165
166 169 }
167
168 170 };
169 171
170 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 };
171 190
172 var plot = YAHOO.widget.Flot("commit_history", data,
173 { bars: { show: true, align:'center',lineWidth:4 },
174 points: { show: true, radius:0,fill:true },
175 legend:{show:true, container:"legend_container"},
176 selection: { mode: "xy" },
177 yaxis: {tickDecimals:0},
178 xaxis: { mode: "time", timeformat: "%d",tickSize:[1, "day"],min:${c.ts_min},max:${c.ts_max} },
179 grid: { hoverable: true, clickable: true,autoHighlight:true },
180 });
181
191 //main plot
192 var plot = YAHOO.widget.Flot("commit_history",data,options);
193
194 //overview
195 var overview = YAHOO.widget.Flot("overview", [overview_data], {
196 legend:{show:false},
197 bars: {show:true,
198 barWidth: 2,
199 },
200 shadowSize: 0,
201 xaxis: {mode: "time",
202 timeformat: "%d/%m/%y",
203 },
204 yaxis: {ticks: 3, min: 0,},
205 grid: {color: "#999",},
206 selection: {mode: "x"}
207 });
208
209 var ranges = {"xaxis":{"from":${c.ts_min},
210 "to":${c.ts_max},},}
211 overview.setSelection(ranges);
212
182 213 function showTooltip(x, y, contents) {
183 214 var div=document.getElementById('tooltip');
184 215 if(!div) {
@@ -198,9 +229,10 b' E.onDOMReady(function(e){'
198 229 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
199 230 anim.animate();
200 231 }
201
232
202 233 var previousPoint = null;
203 plot.subscribe("plothover", function (o) {
234
235 function plothover(o) {
204 236 var pos = o.pos;
205 237 var item = o.item;
206 238
@@ -221,7 +253,7 b' E.onDOMReady(function(e){'
221 253 item.series.label = 'commits';
222 254 }
223 255 var d = new Date(x*1000);
224 var fd = d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate();
256 var fd = d.toDateString()
225 257 var nr_commits = parseInt(y);
226 258
227 259 var cur_data = datasets[item.series.label].data[item.dataIndex];
@@ -256,8 +288,31 b' E.onDOMReady(function(e){'
256 288 }
257 289 previousPoint = null;
258 290 }
259 });
291 }
292
293 plot.subscribe("plothover", plothover);
294
295 function plotselected(ranges) {
296 // do the zooming
297 plot = YAHOO.widget.Flot("commit_history", data,
298 YAHOO.lang.merge(options, {
299 xaxis: { min: ranges.xaxis.from,
300 max: ranges.xaxis.to,
301 mode:"time",
302 timeformat: "%d/%m",
303 }
304 }));
305 plot.subscribe("plotselected", plotselected);
306 plot.subscribe("plothover", plothover);
260 307
308 // don't fire event on the overview to prevent eternal loop
309 overview.setSelection(ranges, true);
310 }
311 plot.subscribe("plotselected", plotselected);
312
313 overview.subscribe("plotselected", function (ranges) {
314 plot.setSelection(ranges);
315 });
261 316 }
262 317 }
263 318
@@ -24,7 +24,7 b' setup('
24 24 "pygments>=1.3.0",
25 25 "mercurial>=1.6",
26 26 "pysqlite",
27 "whoosh==1.0.0b16",
27 "whoosh==1.0.0b17",
28 28 "py-bcrypt",
29 29 "celery",
30 30 ],
General Comments 0
You need to be logged in to leave comments. Login now