##// 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 summary controller for pylons
22 summary controller for pylons
23 @author: marcink
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 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
26 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from pylons_app.lib.base import BaseController, render
27 from pylons_app.lib.base import BaseController, render
28 from pylons_app.lib.utils import OrderedDict
28 from pylons_app.lib.utils import OrderedDict
@@ -61,10 +61,11 b' class SummaryController(BaseController):'
61 for name, hash in c.repo_info.branches.items()[:10]:
61 for name, hash in c.repo_info.branches.items()[:10]:
62 c.repo_branches[name] = c.repo_info.get_changeset(hash)
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 c.ts_min = task.result[0]
65 c.ts_min = task.result[0]
66 c.ts_max = task.result[1]
66 c.ts_max = task.result[1]
67 c.commit_data = task.result[2]
67 c.commit_data = task.result[2]
68 c.overview_data = task.result[3]
68
69
69 return render('summary/summary.html')
70 return render('summary/summary.html')
70
71
@@ -11,6 +11,7 b' from time import mktime'
11 from vcs.backends.hg import MercurialRepository
11 from vcs.backends.hg import MercurialRepository
12 import calendar
12 import calendar
13 import traceback
13 import traceback
14 import json
14
15
15 __all__ = ['whoosh_index', 'get_commits_stats',
16 __all__ = ['whoosh_index', 'get_commits_stats',
16 'reset_user_password', 'send_email']
17 'reset_user_password', 'send_email']
@@ -84,21 +85,26 b' def whoosh_index(repo_location, full_ind'
84 def get_commits_stats(repo):
85 def get_commits_stats(repo):
85 log = get_commits_stats.get_logger()
86 log = get_commits_stats.get_logger()
86 aggregate = OrderedDict()
87 aggregate = OrderedDict()
88 overview_aggregate = OrderedDict()
87 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
89 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
88 repo = MercurialRepository(repos_path + repo)
90 repo = MercurialRepository(repos_path + repo)
89 #graph range
91 #graph range
90 td = datetime.today() + timedelta(days=1)
92 td = datetime.today() + timedelta(days=1)
91 y, m, d = td.year, td.month, td.day
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 d, 0, 0, 0, 0, 0, 0,))
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 def author_key_cleaner(k):
102 def author_key_cleaner(k):
97 k = person(k)
103 k = person(k)
98 k = k.replace('"', "'") #for js data compatibilty
104 k = k.replace('"', "") #for js data compatibilty
99 return k
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 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
108 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
103 cs.date.timetuple()[2])
109 cs.date.timetuple()[2])
104 timetupple = [int(x) for x in k.split('-')]
110 timetupple = [int(x) for x in k.split('-')]
@@ -113,7 +119,7 b' def get_commits_stats(repo):'
113
119
114 else:
120 else:
115 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
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 aggregate[author_key_cleaner(cs.author)][k] = {}
123 aggregate[author_key_cleaner(cs.author)][k] = {}
118 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
124 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
119 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
125 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
@@ -121,7 +127,7 b' def get_commits_stats(repo):'
121 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
127 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
122
128
123 else:
129 else:
124 if k >= ts_min and k <= ts_max:
130 if k >= ts_min_y and k <= ts_max_y:
125 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
131 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
126 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
132 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
127 aggregate[author_key_cleaner(cs.author)][k] = {}
133 aggregate[author_key_cleaner(cs.author)][k] = {}
@@ -130,25 +136,35 b' def get_commits_stats(repo):'
130 aggregate[author_key_cleaner(cs.author)][k]["changed"] = len(cs.changed)
136 aggregate[author_key_cleaner(cs.author)][k]["changed"] = len(cs.changed)
131 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
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,
140 if overview_aggregate.has_key(k):
139 tmpl1 \
141 overview_aggregate[k] += 1
140 % (author,
142 else:
141 [{"time":x,
143 overview_aggregate[k] = 1
142 "commits":aggregate[author][x]['commits'],
144
143 "added":aggregate[author][x]['added'],
145 overview_data = []
144 "changed":aggregate[author][x]['changed'],
146 for k, v in overview_aggregate.items():
145 "removed":aggregate[author][x]['removed'],
147 overview_data.append([k, v])
146 } for x in aggregate[author]]))
148 data = {}
147 if d == '':
149 for author in aggregate:
148 d = '"%s":{label:"%s",data:[[0,1],]}' \
150 data[author] = {"label":author,
149 % (author_key_cleaner(repo.contact),
151 "data":[{"time":x,
150 author_key_cleaner(repo.contact))
152 "commits":aggregate[author][x]['commits'],
151 return (ts_min, ts_max, d)
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 @task
169 @task
154 def reset_user_password(user_email):
170 def reset_user_password(user_email):
@@ -157,7 +173,6 b' def reset_user_password(user_email):'
157 from pylons_app.model.db import User
173 from pylons_app.model.db import User
158
174
159 try:
175 try:
160
161 try:
176 try:
162 sa = get_session()
177 sa = get_session()
163 user = sa.query(User).filter(User.email == user_email).scalar()
178 user = sa.query(User).filter(User.email == user_email).scalar()
@@ -126,7 +126,10 b' E.onDOMReady(function(e){'
126
126
127 <div class="table">
127 <div class="table">
128 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
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 <div id="legend_container"></div>
133 <div id="legend_container"></div>
131 <div id="legend_choices">
134 <div id="legend_choices">
132 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
135 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
@@ -135,7 +138,9 b' E.onDOMReady(function(e){'
135 <script type="text/javascript">
138 <script type="text/javascript">
136
139
137 (function () {
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 var i = 0;
144 var i = 0;
140 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
145 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
141 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
146 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
@@ -147,8 +152,7 b' E.onDOMReady(function(e){'
147 +datasets[key].label+
152 +datasets[key].label+
148 '</td></tr>';
153 '</td></tr>';
149 };
154 };
150
155
151
152 function plotAccordingToChoices() {
156 function plotAccordingToChoices() {
153 var data = [];
157 var data = [];
154
158
@@ -162,23 +166,50 b' E.onDOMReady(function(e){'
162 else{
166 else{
163 data.push(datasets[key]);
167 data.push(datasets[key]);
164 }
168 }
165
166 }
169 }
167
168 };
170 };
169
171
170 if (data.length > 0){
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,
191 //main plot
173 { bars: { show: true, align:'center',lineWidth:4 },
192 var plot = YAHOO.widget.Flot("commit_history",data,options);
174 points: { show: true, radius:0,fill:true },
193
175 legend:{show:true, container:"legend_container"},
194 //overview
176 selection: { mode: "xy" },
195 var overview = YAHOO.widget.Flot("overview", [overview_data], {
177 yaxis: {tickDecimals:0},
196 legend:{show:false},
178 xaxis: { mode: "time", timeformat: "%d",tickSize:[1, "day"],min:${c.ts_min},max:${c.ts_max} },
197 bars: {show:true,
179 grid: { hoverable: true, clickable: true,autoHighlight:true },
198 barWidth: 2,
180 });
199 },
181
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 function showTooltip(x, y, contents) {
213 function showTooltip(x, y, contents) {
183 var div=document.getElementById('tooltip');
214 var div=document.getElementById('tooltip');
184 if(!div) {
215 if(!div) {
@@ -198,9 +229,10 b' E.onDOMReady(function(e){'
198 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
229 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
199 anim.animate();
230 anim.animate();
200 }
231 }
201
232
202 var previousPoint = null;
233 var previousPoint = null;
203 plot.subscribe("plothover", function (o) {
234
235 function plothover(o) {
204 var pos = o.pos;
236 var pos = o.pos;
205 var item = o.item;
237 var item = o.item;
206
238
@@ -221,7 +253,7 b' E.onDOMReady(function(e){'
221 item.series.label = 'commits';
253 item.series.label = 'commits';
222 }
254 }
223 var d = new Date(x*1000);
255 var d = new Date(x*1000);
224 var fd = d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate();
256 var fd = d.toDateString()
225 var nr_commits = parseInt(y);
257 var nr_commits = parseInt(y);
226
258
227 var cur_data = datasets[item.series.label].data[item.dataIndex];
259 var cur_data = datasets[item.series.label].data[item.dataIndex];
@@ -256,8 +288,31 b' E.onDOMReady(function(e){'
256 }
288 }
257 previousPoint = null;
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 "pygments>=1.3.0",
24 "pygments>=1.3.0",
25 "mercurial>=1.6",
25 "mercurial>=1.6",
26 "pysqlite",
26 "pysqlite",
27 "whoosh==1.0.0b16",
27 "whoosh==1.0.0b17",
28 "py-bcrypt",
28 "py-bcrypt",
29 "celery",
29 "celery",
30 ],
30 ],
General Comments 0
You need to be logged in to leave comments. Login now