##// 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
@@ -1,26 +1,29 b''
1 1 from vcs.utils.lazy import LazyProperty
2 2 import logging
3 3 import os
4 4 import sys
5 5 import traceback
6 6
7 7 log = logging.getLogger(__name__)
8 8
9 9 class ResultWrapper(object):
10 10 def __init__(self, task):
11 11 self.task = task
12 12
13 13 @LazyProperty
14 14 def result(self):
15 15 return self.task
16 16
17 def run_task(task,*args,**kwargs):
17 def run_task(task, *args, **kwargs):
18 18 try:
19 t = task.delay(*args,**kwargs)
20 log.info('running task %s',t.task_id)
19 t = task.delay(*args, **kwargs)
20 log.info('running task %s', t.task_id)
21 21 return t
22 except:
23 log.error(traceback.format_exc())
22 except Exception, e:
23 if e.errno == 111:
24 log.debug('Unnable to connect. Sync execution')
25 else:
26 log.error(traceback.format_exc())
24 27 #pure sync version
25 return ResultWrapper(task(*args,**kwargs))
26 No newline at end of file
28 return ResultWrapper(task(*args, **kwargs))
29
@@ -1,223 +1,229 b''
1 1 from celery.decorators import task
2 2 from celery.task.sets import subtask
3 3 from celeryconfig import PYLONS_CONFIG as config
4 4 from datetime import datetime, timedelta
5 5 from pylons.i18n.translation import _
6 6 from pylons_app.lib.celerylib import run_task
7 7 from pylons_app.lib.helpers import person
8 8 from pylons_app.lib.smtp_mailer import SmtpMailer
9 9 from pylons_app.lib.utils import OrderedDict
10 from operator import itemgetter
11 from vcs.backends.hg import MercurialRepository
10 12 from time import mktime
11 from vcs.backends.hg import MercurialRepository
12 13 import calendar
13 14 import traceback
14 15 import json
15 16
16 17 __all__ = ['whoosh_index', 'get_commits_stats',
17 18 'reset_user_password', 'send_email']
18 19
19 20 def get_session():
20 21 from sqlalchemy import engine_from_config
21 22 from sqlalchemy.orm import sessionmaker, scoped_session
22 23 engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
23 24 sa = scoped_session(sessionmaker(bind=engine))
24 25 return sa
25 26
26 27 def get_hg_settings():
27 28 from pylons_app.model.db import HgAppSettings
28 29 try:
29 30 sa = get_session()
30 31 ret = sa.query(HgAppSettings).all()
31 32 finally:
32 33 sa.remove()
33 34
34 35 if not ret:
35 36 raise Exception('Could not get application settings !')
36 37 settings = {}
37 38 for each in ret:
38 39 settings['hg_app_' + each.app_settings_name] = each.app_settings_value
39 40
40 41 return settings
41 42
42 43 def get_hg_ui_settings():
43 44 from pylons_app.model.db import HgAppUi
44 45 try:
45 46 sa = get_session()
46 47 ret = sa.query(HgAppUi).all()
47 48 finally:
48 49 sa.remove()
49 50
50 51 if not ret:
51 52 raise Exception('Could not get application ui settings !')
52 53 settings = {}
53 54 for each in ret:
54 55 k = each.ui_key
55 56 v = each.ui_value
56 57 if k == '/':
57 58 k = 'root_path'
58 59
59 60 if k.find('.') != -1:
60 61 k = k.replace('.', '_')
61 62
62 63 if each.ui_section == 'hooks':
63 64 v = each.ui_active
64 65
65 66 settings[each.ui_section + '_' + k] = v
66 67
67 68 return settings
68 69
69 70 @task
70 71 def whoosh_index(repo_location, full_index):
71 72 log = whoosh_index.get_logger()
72 73 from pylons_app.lib.indexers import DaemonLock
73 74 from pylons_app.lib.indexers.daemon import WhooshIndexingDaemon, LockHeld
74 75 try:
75 76 l = DaemonLock()
76 77 WhooshIndexingDaemon(repo_location=repo_location)\
77 78 .run(full_index=full_index)
78 79 l.release()
79 80 return 'Done'
80 81 except LockHeld:
81 82 log.info('LockHeld')
82 83 return 'LockHeld'
83 84
84 85 @task
85 86 def get_commits_stats(repo):
86 87 log = get_commits_stats.get_logger()
87 88 aggregate = OrderedDict()
88 89 overview_aggregate = OrderedDict()
89 90 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*', '')
90 91 repo = MercurialRepository(repos_path + repo)
91 92 #graph range
92 93 td = datetime.today() + timedelta(days=1)
93 94 y, m, d = td.year, td.month, td.day
94 95
95 96 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
96 97 d, 0, 0, 0, 0, 0, 0,))
97 98 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
98 99 d, 0, 0, 0, 0, 0, 0,))
99 100
100 101 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
101
102 skip_date_limit = True
103
102 104 def author_key_cleaner(k):
103 105 k = person(k)
104 106 k = k.replace('"', "") #for js data compatibilty
105 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 110 k = '%s-%s-%s' % (cs.date.timetuple()[0], cs.date.timetuple()[1],
109 111 cs.date.timetuple()[2])
110 112 timetupple = [int(x) for x in k.split('-')]
111 113 timetupple.extend([0 for _ in xrange(6)])
112 114 k = mktime(timetupple)
113 115 if aggregate.has_key(author_key_cleaner(cs.author)):
114 116 if aggregate[author_key_cleaner(cs.author)].has_key(k):
115 117 aggregate[author_key_cleaner(cs.author)][k]["commits"] += 1
116 118 aggregate[author_key_cleaner(cs.author)][k]["added"] += len(cs.added)
117 119 aggregate[author_key_cleaner(cs.author)][k]["changed"] += len(cs.changed)
118 120 aggregate[author_key_cleaner(cs.author)][k]["removed"] += len(cs.removed)
119 121
120 122 else:
121 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 125 aggregate[author_key_cleaner(cs.author)][k] = {}
124 126 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
125 127 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
126 128 aggregate[author_key_cleaner(cs.author)][k]["changed"] = len(cs.changed)
127 129 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
128 130
129 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 133 aggregate[author_key_cleaner(cs.author)] = OrderedDict()
132 134 #aggregate[author_key_cleaner(cs.author)].update(dates_range)
133 135 aggregate[author_key_cleaner(cs.author)][k] = {}
134 136 aggregate[author_key_cleaner(cs.author)][k]["commits"] = 1
135 137 aggregate[author_key_cleaner(cs.author)][k]["added"] = len(cs.added)
136 138 aggregate[author_key_cleaner(cs.author)][k]["changed"] = len(cs.changed)
137 139 aggregate[author_key_cleaner(cs.author)][k]["removed"] = len(cs.removed)
138 140
139 141
140 142 if overview_aggregate.has_key(k):
141 143 overview_aggregate[k] += 1
142 144 else:
143 145 overview_aggregate[k] = 1
144 146
145 147 overview_data = []
146 148 for k, v in overview_aggregate.items():
147 149 overview_data.append([k, v])
150 overview_data = sorted(overview_data, key=itemgetter(0))
148 151 data = {}
149 152 for author in aggregate:
150 data[author] = {"label":author,
151 "data":[{"time":x,
153 commit_data = sorted([{"time":x,
152 154 "commits":aggregate[author][x]['commits'],
153 155 "added":aggregate[author][x]['added'],
154 156 "changed":aggregate[author][x]['changed'],
155 157 "removed":aggregate[author][x]['removed'],
156 158 } for x in aggregate[author]],
159 key=itemgetter('time'))
160
161 data[author] = {"label":author,
162 "data":commit_data,
157 163 "schema":["commits"]
158 164 }
159 165
160 166 if not data:
161 167 data[author_key_cleaner(repo.contact)] = {
162 168 "label":author_key_cleaner(repo.contact),
163 169 "data":[0, 1],
164 170 "schema":["commits"],
165 171 }
166 172
167 173 return (ts_min_m, ts_max_y, json.dumps(data), json.dumps(overview_data))
168 174
169 175 @task
170 176 def reset_user_password(user_email):
171 177 log = reset_user_password.get_logger()
172 178 from pylons_app.lib import auth
173 179 from pylons_app.model.db import User
174 180
175 181 try:
176 182 try:
177 183 sa = get_session()
178 184 user = sa.query(User).filter(User.email == user_email).scalar()
179 185 new_passwd = auth.PasswordGenerator().gen_password(8,
180 186 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
181 187 user.password = auth.get_crypt_password(new_passwd)
182 188 sa.add(user)
183 189 sa.commit()
184 190 log.info('change password for %s', user_email)
185 191 if new_passwd is None:
186 192 raise Exception('unable to generate new password')
187 193
188 194 except:
189 195 log.error(traceback.format_exc())
190 196 sa.rollback()
191 197
192 198 run_task(send_email, user_email,
193 199 "Your new hg-app password",
194 200 'Your new hg-app password:%s' % (new_passwd))
195 201 log.info('send new password mail to %s', user_email)
196 202
197 203
198 204 except:
199 205 log.error('Failed to update user password')
200 206 log.error(traceback.format_exc())
201 207 return True
202 208
203 209 @task
204 210 def send_email(recipients, subject, body):
205 211 log = send_email.get_logger()
206 212 email_config = dict(config.items('DEFAULT'))
207 213 mail_from = email_config.get('app_email_from')
208 214 user = email_config.get('smtp_username')
209 215 passwd = email_config.get('smtp_password')
210 216 mail_server = email_config.get('smtp_server')
211 217 mail_port = email_config.get('smtp_port')
212 218 tls = email_config.get('smtp_use_tls')
213 219 ssl = False
214 220
215 221 try:
216 222 m = SmtpMailer(mail_from, user, passwd, mail_server,
217 223 mail_port, ssl, tls)
218 224 m.send(recipients, subject, body)
219 225 except:
220 226 log.error('Mail sending failed')
221 227 log.error(traceback.format_exc())
222 228 return False
223 229 return True
@@ -1,356 +1,508 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${_('Mercurial Repository Overview')}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(u'Home',h.url('/'))}
9 9 &raquo;
10 10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 11 &raquo;
12 12 ${_('summary')}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('summary')}
17 17 </%def>
18 18
19 19 <%def name="main()">
20 20 <script type="text/javascript">
21 21 var E = YAHOO.util.Event;
22 22 var D = YAHOO.util.Dom;
23 23
24 24 E.onDOMReady(function(e){
25 25 id = 'clone_url';
26 26 E.addListener(id,'click',function(e){
27 27 D.get('clone_url').select();
28 28 })
29 29 })
30 30 </script>
31 31 <div class="box box-left">
32 32 <!-- box / title -->
33 33 <div class="title">
34 34 ${self.breadcrumbs()}
35 35 </div>
36 36 <!-- end box / title -->
37 37 <div class="form">
38 38 <div class="fields">
39 39
40 40 <div class="field">
41 41 <div class="label">
42 42 <label>${_('Name')}:</label>
43 43 </div>
44 44 <div class="input-short">
45 45 <span style="font-size: 1.6em;font-weight: bold">${c.repo_info.name}</span>
46 46 </div>
47 47 </div>
48 48
49 49
50 50 <div class="field">
51 51 <div class="label">
52 52 <label>${_('Description')}:</label>
53 53 </div>
54 54 <div class="input-short">
55 55 ${c.repo_info.description}
56 56 </div>
57 57 </div>
58 58
59 59
60 60 <div class="field">
61 61 <div class="label">
62 62 <label>${_('Contact')}:</label>
63 63 </div>
64 64 <div class="input-short">
65 65 <div class="gravatar">
66 66 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
67 67 </div>
68 68 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
69 69 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
70 70 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
71 71 </div>
72 72 </div>
73 73
74 74 <div class="field">
75 75 <div class="label">
76 76 <label>${_('Last change')}:</label>
77 77 </div>
78 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 82 </div>
81 83 </div>
82 84
83 85 <div class="field">
84 86 <div class="label">
85 87 <label>${_('Clone url')}:</label>
86 88 </div>
87 89 <div class="input-short">
88 90 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
89 91 </div>
90 92 </div>
91 93
92 94 <div class="field">
93 95 <div class="label">
94 96 <label>${_('Download')}:</label>
95 97 </div>
96 98 <div class="input-short">
97 99 %for cnt,archive in enumerate(c.repo_info._get_archives()):
98 100 %if cnt >=1:
99 101 |
100 102 %endif
101 103 ${h.link_to(c.repo_info.name+'.'+archive['type'],
102 104 h.url('files_archive_home',repo_name=c.repo_info.name,
103 105 revision='tip',fileformat=archive['extension']),class_="archive_icon")}
104 106 %endfor
105 107 </div>
106 108 </div>
107 109
108 110 <div class="field">
109 111 <div class="label">
110 112 <label>${_('Feeds')}:</label>
111 113 </div>
112 114 <div class="input-short">
113 115 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
114 116 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
115 117 </div>
116 118 </div>
117 119 </div>
118 120 </div>
119 121 </div>
120 122
121 123 <div class="box box-right" style="min-height:455px">
122 124 <!-- box / title -->
123 125 <div class="title">
124 <h5>${_('Last month commit activity')}</h5>
126 <h5>${_('Commit activity')}</h5>
125 127 </div>
126 128
127 129 <div class="table">
128 130 <div id="commit_history" style="width:560px;height:300px;float:left"></div>
129 131 <div style="clear: both;height: 10px"></div>
130 132 <div id="overview" style="width:560px;height:100px;float:left"></div>
131 133
132 134 <div id="legend_data" style="clear:both;margin-top:10px;">
133 135 <div id="legend_container"></div>
134 136 <div id="legend_choices">
135 137 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
136 138 </div>
137 139 </div>
138 140 <script type="text/javascript">
139
140 (function () {
141 var datasets = ${c.commit_data|n};
142 var overview_data = ${c.overview_data|n};
143
144 var i = 0;
141 /**
142 * Plots summary graph
143 *
144 * @class SummaryPlot
145 * @param {from} initial from for detailed graph
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 159 var choiceContainer = YAHOO.util.Dom.get("legend_choices");
146 160 var choiceContainerTable = YAHOO.util.Dom.get("legend_choices_tables");
147 for(var key in datasets) {
148 datasets[key].color = i;
149 i++;
150 choiceContainerTable.innerHTML += '<tr><td>'+
151 '<input type="checkbox" name="' + key +'" checked="checked" />'
152 +datasets[key].label+
153 '</td></tr>';
161 var plotContainer = YAHOO.util.Dom.get('commit_history');
162 var overviewContainer = YAHOO.util.Dom.get('overview');
163
164 var plot_options = {
165 bars: {show:true,align:'center',lineWidth:4},
166 legend: {show:true, container:"legend_container"},
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
156 function plotAccordingToChoices() {
157 var data = [];
158
159 var inputs = choiceContainer.getElementsByTagName("input");
160 for(var i=0; i<inputs.length; i++) {
161 var key = inputs[i].name;
162 if (key && datasets[key]){
163 if(!inputs[i].checked){
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 };
183 var overview_options = {
184 legend:{show:false},
185 bars: {show:true,barWidth: 2,},
186 shadowSize: 0,
187 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
188 yaxis: {ticks: 3, min: 0,},
189 grid: {color: "#999",},
190 selection: {mode: "x"}
191 };
190 192
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 });
193 /**
194 *get dummy data needed in few places
195 */
196 function getDummyData(label){
197 return {"label":label,
198 "data":[{"time":0,
199 "commits":0,
200 "added":0,
201 "changed":0,
202 "removed":0,
203 }],
204 "schema":["commits"],
205 "color":'#ffffff',
206 }
207 }
208
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},
210 "to":${c.ts_max},},}
211 overview.setSelection(ranges);
212
213 function showTooltip(x, y, contents) {
214 var div=document.getElementById('tooltip');
215 if(!div) {
216 div = document.createElement('div');
217 div.id="tooltip";
218 div.style.position="absolute";
219 div.style.border='1px solid #fdd';
220 div.style.padding='2px';
221 div.style.backgroundColor='#fee';
222 document.body.appendChild(div);
223 }
224 YAHOO.util.Dom.setStyle(div, 'opacity', 0);
225 div.innerHTML = contents;
226 div.style.top=(y + 5) + "px";
227 div.style.left=(x + 5) + "px";
228
229 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
230 anim.animate();
250 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
251 anim.animate();
252 }
253
254 /**
255 * This function will detect if selected period has some changesets for this user
256 if it does this data is then pushed for displaying
257 Additionally it will only display users that are selected by the checkbox
258 */
259 function getDataAccordingToRanges(ranges) {
260
261 var data = [];
262 var keys = [];
263 for(var key in dataset){
264 var push = false;
265 //method1 slow !!
266 ///*
267 for(var ds in dataset[key].data){
268 commit_data = dataset[key].data[ds];
269 //console.log(key);
270 //console.log(new Date(commit_data.time*1000));
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) {
236 var pos = o.pos;
237 var item = o.item;
238
239 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
240 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
241 if (item) {
242 if (previousPoint != item.datapoint) {
243 previousPoint = item.datapoint;
244
245 var tooltip = YAHOO.util.Dom.get("tooltip");
246 if(tooltip) {
247 tooltip.parentNode.removeChild(tooltip);
248 }
249 var x = item.datapoint.x.toFixed(2);
250 var y = item.datapoint.y.toFixed(2);
251
252 if (!item.series.label){
253 item.series.label = 'commits';
254 }
255 var d = new Date(x*1000);
256 var fd = d.toDateString()
257 var nr_commits = parseInt(y);
258
259 var cur_data = datasets[item.series.label].data[item.dataIndex];
260 var added = cur_data.added;
261 var changed = cur_data.changed;
262 var removed = cur_data.removed;
263
264 var nr_commits_suffix = " ${_('commits')} ";
265 var added_suffix = " ${_('files added')} ";
266 var changed_suffix = " ${_('files changed')} ";
267 var removed_suffix = " ${_('files removed')} ";
314 //show only checked labels
315 for(var i=0; i<inputs.length; i++) {
316 var checkbox_key = inputs[i].name;
317
318 if(inputs[i].checked){
319 for(var d in cur_data){
320 if(cur_data[d].label == checkbox_key){
321 new_data.push(cur_data[d]);
322 }
323 }
324 }
325 else{
326 //push dummy data to not hide the label
327 new_data.push(getDummyData(checkbox_key));
328 }
329 }
330
331 var new_options = YAHOO.lang.merge(plot_options, {
332 xaxis: {
333 min: cur_ranges.xaxis.from,
334 max: cur_ranges.xaxis.to,
335 mode:"time",
336 timeformat: "%d/%m",
337 }
338 });
339 if (!new_data){
340 new_data = [[0,1]];
341 }
342 // do the zooming
343 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
344
345 plot.subscribe("plotselected", plotselected);
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
270 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
271 if(added==1){added_suffix=" ${_('file added')} ";}
272 if(changed==1){changed_suffix=" ${_('file changed')} ";}
273 if(removed==1){removed_suffix=" ${_('file removed')} ";}
274
275 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
276 +'<br/>'+
277 nr_commits + nr_commits_suffix+'<br/>'+
278 added + added_suffix +'<br/>'+
279 changed + changed_suffix + '<br/>'+
280 removed + removed_suffix + '<br/>');
281 }
390 function plothover(o) {
391 var pos = o.pos;
392 var item = o.item;
393
394 //YAHOO.util.Dom.get("x").innerHTML = pos.x.toFixed(2);
395 //YAHOO.util.Dom.get("y").innerHTML = pos.y.toFixed(2);
396 if (item) {
397 if (previousPoint != item.datapoint) {
398 previousPoint = item.datapoint;
399
400 var tooltip = YAHOO.util.Dom.get("tooltip");
401 if(tooltip) {
402 tooltip.parentNode.removeChild(tooltip);
282 403 }
283 else {
284 var tooltip = YAHOO.util.Dom.get("tooltip");
285
286 if(tooltip) {
287 tooltip.parentNode.removeChild(tooltip);
288 }
289 previousPoint = null;
404 var x = item.datapoint.x.toFixed(2);
405 var y = item.datapoint.y.toFixed(2);
406
407 if (!item.series.label){
408 item.series.label = 'commits';
290 409 }
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);
410 var d = new Date(x*1000);
411 var fd = d.toDateString()
412 var nr_commits = parseInt(y);
413
414 var cur_data = dataset[item.series.label].data[item.dataIndex];
415 var added = cur_data.added;
416 var changed = cur_data.changed;
417 var removed = cur_data.removed;
418
419 var nr_commits_suffix = " ${_('commits')} ";
420 var added_suffix = " ${_('files added')} ";
421 var changed_suffix = " ${_('files changed')} ";
422 var removed_suffix = " ${_('files removed')} ";
307 423
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 });
316 }
424
425 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
426 if(added==1){added_suffix=" ${_('file added')} ";}
427 if(changed==1){changed_suffix=" ${_('file changed')} ";}
428 if(removed==1){removed_suffix=" ${_('file removed')} ";}
429
430 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
431 +'<br/>'+
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
319 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotAccordingToChoices);
447
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();
322 })();
323 </script>
472 YAHOO.util.Event.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
473 }
474 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
475 </script>
324 476
325 477 </div>
326 478 </div>
327 479
328 480 <div class="box">
329 481 <div class="title">
330 482 <div class="breadcrumbs">${h.link_to(_('Last ten changes'),h.url('changelog_home',repo_name=c.repo_name))}</div>
331 483 </div>
332 484 <div class="table">
333 485 <%include file='../shortlog/shortlog_data.html'/>
334 486 ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
335 487 </div>
336 488 </div>
337 489 <div class="box">
338 490 <div class="title">
339 491 <div class="breadcrumbs">${h.link_to(_('Last ten tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
340 492 </div>
341 493 <div class="table">
342 494 <%include file='../tags/tags_data.html'/>
343 495 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
344 496 </div>
345 497 </div>
346 498 <div class="box">
347 499 <div class="title">
348 500 <div class="breadcrumbs">${h.link_to(_('Last ten branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
349 501 </div>
350 502 <div class="table">
351 503 <%include file='../branches/branches_data.html'/>
352 504 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
353 505 </div>
354 506 </div>
355 507
356 508 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now