##// END OF EJS Templates
fixes #668 cherry picking of changeset should also work now on picking single changesets, and the ones from top
marcink -
r3076:5deb16cd beta
parent child Browse files
Show More
@@ -1,280 +1,285 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.pull_request
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 pull request model for RhodeCode
7 7
8 8 :created_on: Jun 6, 2012
9 9 :author: marcink
10 10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import binascii
28 28 import datetime
29 29 import re
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from rhodecode.model.meta import Session
34 34 from rhodecode.lib import helpers as h
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification
37 37 from rhodecode.model.notification import NotificationModel
38 38 from rhodecode.lib.utils2 import safe_unicode
39 39
40 40 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
41 41 findcommonoutgoing
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 class PullRequestModel(BaseModel):
47 47
48 48 cls = PullRequest
49 49
50 50 def __get_pull_request(self, pull_request):
51 51 return self._get_instance(PullRequest, pull_request)
52 52
53 53 def get_all(self, repo):
54 54 repo = self._get_repo(repo)
55 55 return PullRequest.query().filter(PullRequest.other_repo == repo).all()
56 56
57 57 def create(self, created_by, org_repo, org_ref, other_repo,
58 58 other_ref, revisions, reviewers, title, description=None):
59 59
60 60 created_by_user = self._get_user(created_by)
61 61 org_repo = self._get_repo(org_repo)
62 62 other_repo = self._get_repo(other_repo)
63 63
64 64 new = PullRequest()
65 65 new.org_repo = org_repo
66 66 new.org_ref = org_ref
67 67 new.other_repo = other_repo
68 68 new.other_ref = other_ref
69 69 new.revisions = revisions
70 70 new.title = title
71 71 new.description = description
72 72 new.author = created_by_user
73 73 self.sa.add(new)
74 74 Session().flush()
75 75 #members
76 76 for member in reviewers:
77 77 _usr = self._get_user(member)
78 78 reviewer = PullRequestReviewers(_usr, new)
79 79 self.sa.add(reviewer)
80 80
81 81 #notification to reviewers
82 82 notif = NotificationModel()
83 83
84 84 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
85 85 pull_request_id=new.pull_request_id,
86 86 qualified=True,
87 87 )
88 88 subject = safe_unicode(
89 89 h.link_to(
90 90 _('%(user)s wants you to review pull request #%(pr_id)s') % \
91 91 {'user': created_by_user.username,
92 92 'pr_id': new.pull_request_id},
93 93 pr_url
94 94 )
95 95 )
96 96 body = description
97 97 kwargs = {
98 98 'pr_title': title,
99 99 'pr_user_created': h.person(created_by_user.email),
100 100 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
101 101 qualified=True,),
102 102 'pr_url': pr_url,
103 103 'pr_revisions': revisions
104 104 }
105 105 notif.create(created_by=created_by_user, subject=subject, body=body,
106 106 recipients=reviewers,
107 107 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
108 108 return new
109 109
110 110 def update_reviewers(self, pull_request, reviewers_ids):
111 111 reviewers_ids = set(reviewers_ids)
112 112 pull_request = self.__get_pull_request(pull_request)
113 113 current_reviewers = PullRequestReviewers.query()\
114 114 .filter(PullRequestReviewers.pull_request==
115 115 pull_request)\
116 116 .all()
117 117 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
118 118
119 119 to_add = reviewers_ids.difference(current_reviewers_ids)
120 120 to_remove = current_reviewers_ids.difference(reviewers_ids)
121 121
122 122 log.debug("Adding %s reviewers" % to_add)
123 123 log.debug("Removing %s reviewers" % to_remove)
124 124
125 125 for uid in to_add:
126 126 _usr = self._get_user(uid)
127 127 reviewer = PullRequestReviewers(_usr, pull_request)
128 128 self.sa.add(reviewer)
129 129
130 130 for uid in to_remove:
131 131 reviewer = PullRequestReviewers.query()\
132 132 .filter(PullRequestReviewers.user_id==uid,
133 133 PullRequestReviewers.pull_request==pull_request)\
134 134 .scalar()
135 135 if reviewer:
136 136 self.sa.delete(reviewer)
137 137
138 138 def delete(self, pull_request):
139 139 pull_request = self.__get_pull_request(pull_request)
140 140 Session().delete(pull_request)
141 141
142 142 def close_pull_request(self, pull_request):
143 143 pull_request = self.__get_pull_request(pull_request)
144 144 pull_request.status = PullRequest.STATUS_CLOSED
145 145 pull_request.updated_on = datetime.datetime.now()
146 146 self.sa.add(pull_request)
147 147
148 148 def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref,
149 149 discovery_data):
150 150 """
151 151 Returns a list of changesets that are incoming from org_repo@org_ref
152 152 to other_repo@other_ref
153 153
154 154 :param org_repo:
155 155 :param org_ref:
156 156 :param other_repo:
157 157 :param other_ref:
158 158 :param tmp:
159 159 """
160 160
161 161 changesets = []
162 162 #case two independent repos
163 163 common, incoming, rheads = discovery_data
164 164 if org_repo != other_repo:
165 165 revs = [
166 166 org_repo._repo.lookup(org_ref[1]),
167 167 org_repo._repo.lookup(other_ref[1]),
168 168 ]
169 169
170 170 obj = findcommonoutgoing(org_repo._repo,
171 171 localrepo.locallegacypeer(other_repo._repo.local()),
172 172 revs,
173 173 force=True)
174 174 revs = obj.missing
175 175
176 176 for cs in map(binascii.hexlify, revs):
177 177 _cs = org_repo.get_changeset(cs)
178 178 changesets.append(_cs)
179 # in case we have revisions filter out the ones not in given range
180 if org_ref[0] == 'rev' and other_ref[0] == 'rev':
181 revs = [x.raw_id for x in changesets]
182 start = org_ref[1]
183 stop = other_ref[1]
184 changesets = changesets[revs.index(start):revs.index(stop) + 1]
179 185 else:
180 186 #no remote compare do it on the same repository
181 187 if alias == 'hg':
182 188 _revset_predicates = {
183 189 'branch': 'branch',
184 190 'book': 'bookmark',
185 191 'tag': 'tag',
186 192 'rev': 'id',
187 193 }
188 194
189 195 revs = [
190 196 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
191 197 _revset_predicates[other_ref[0]], other_ref[1],
192 198 _revset_predicates[org_ref[0]], org_ref[1],
193 199 )
194 200 ]
195 201
196 202 out = scmutil.revrange(org_repo._repo, revs)
197 203 for cs in (out):
198 204 changesets.append(org_repo.get_changeset(cs))
199 205 elif alias == 'git':
200 206 so, se = org_repo.run_git_command(
201 207 'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
202 208 other_ref[1])
203 209 )
204 210 ids = re.findall(r'[0-9a-fA-F]{40}', so)
205 211 for cs in (ids):
206 212 changesets.append(org_repo.get_changeset(cs))
207 213
208 214 return changesets
209 215
210 216 def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
211 217 """
212 218 Get's mercurial discovery data used to calculate difference between
213 219 repos and refs
214 220
215 221 :param org_repo:
216 222 :type org_repo:
217 223 :param org_ref:
218 224 :type org_ref:
219 225 :param other_repo:
220 226 :type other_repo:
221 227 :param other_ref:
222 228 :type other_ref:
223 229 """
224 230
225 231 _org_repo = org_repo._repo
226 232 org_rev_type, org_rev = org_ref
227 233
228 234 _other_repo = other_repo._repo
229 235 other_rev_type, other_rev = other_ref
230 236
231 237 log.debug('Doing discovery for %s@%s vs %s@%s' % (
232 238 org_repo, org_ref, other_repo, other_ref)
233 239 )
234 240
235 241 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
236 242 org_peer = localrepo.locallegacypeer(_org_repo.local())
237 243 tmp = discovery.findcommonincoming(
238 244 repo=_other_repo, # other_repo we check for incoming
239 245 remote=org_peer, # org_repo source for incoming
240 246 # heads=[_other_repo[other_rev].node(),
241 247 # _org_repo[org_rev].node()],
242 248 force=True
243 249 )
244 250 return tmp
245 251
246 252 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
247 253 """
248 254 Returns a tuple of incomming changesets, and discoverydata cache for
249 255 mercurial repositories
250 256
251 257 :param org_repo:
252 258 :type org_repo:
253 259 :param org_ref:
254 260 :type org_ref:
255 261 :param other_repo:
256 262 :type other_repo:
257 263 :param other_ref:
258 264 :type other_ref:
259 265 """
260 266
261 267 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
262 268 raise Exception('org_ref must be a two element list/tuple')
263 269
264 270 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
265 271 raise Exception('other_ref must be a two element list/tuple')
266 272
267 273 org_repo_scm = org_repo.scm_instance
268 274 other_repo_scm = other_repo.scm_instance
269 275
270 276 alias = org_repo.scm_instance.alias
271 277 discovery_data = [None, None, None]
272 278 if alias == 'hg':
273 279 discovery_data = self._get_discovery(org_repo_scm, org_ref,
274 280 other_repo_scm, other_ref)
275 281 cs_ranges = self._get_changesets(alias,
276 282 org_repo_scm, org_ref,
277 283 other_repo_scm, other_ref,
278 284 discovery_data)
279
280 285 return cs_ranges, discovery_data
@@ -1,305 +1,305 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.html"/>
4 4
5 5 <%def name="title()">
6 6 ${_('%s Changelog') % c.repo_name} - ${c.rhodecode_name}
7 7 </%def>
8 8
9 9 <%def name="breadcrumbs_links()">
10 10 ${h.link_to(_(u'Home'),h.url('/'))}
11 11 &raquo;
12 12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 13 &raquo;
14 14 <% size = c.size if c.size <= c.total_cs else c.total_cs %>
15 15 ${_('Changelog')} - ${ungettext('showing %d out of %d revision', 'showing %d out of %d revisions', size) % (size, c.total_cs)}
16 16 </%def>
17 17
18 18 <%def name="page_nav()">
19 19 ${self.menu('changelog')}
20 20 </%def>
21 21
22 22 <%def name="main()">
23 23 <div class="box">
24 24 <!-- box / title -->
25 25 <div class="title">
26 26 ${self.breadcrumbs()}
27 27 </div>
28 28 <div class="table">
29 29 % if c.pagination:
30 30 <div id="graph">
31 31 <div id="graph_nodes">
32 32 <canvas id="graph_canvas"></canvas>
33 33 </div>
34 34 <div id="graph_content">
35 35 <div class="info_box" style="clear: both;padding: 10px 6px;vertical-align: right;text-align: right;">
36 36 <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
37 37 <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
38 38
39 39 %if c.rhodecode_db_repo.fork:
40 40 <a title="${_('compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name)}" class="ui-btn small">${_('Compare fork with parent')}</a>
41 41 %endif
42 42 %if h.is_hg(c.rhodecode_repo):
43 43 <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
44 44 %endif
45 45 </div>
46 46 <div class="container_header">
47 47 ${h.form(h.url.current(),method='get')}
48 48 <div class="info_box" style="float:left">
49 49 ${h.submit('set',_('Show'),class_="ui-btn")}
50 50 ${h.text('size',size=1,value=c.size)}
51 51 ${_('revisions')}
52 52 </div>
53 53 ${h.end_form()}
54 54 <div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
55 55 </div>
56 56
57 57 %for cnt,cs in enumerate(c.pagination):
58 58 <div id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
59 59 <div class="left">
60 60 <div>
61 61 ${h.checkbox(cs.raw_id,class_="changeset_range")}
62 62 <span class="tooltip" title="${h.tooltip(h.age(cs.date))}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}"><span class="changeset_id">${cs.revision}:<span class="changeset_hash">${h.short_id(cs.raw_id)}</span></span></a></span>
63 63 </div>
64 64 <div class="author">
65 65 <div class="gravatar">
66 66 <img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),16)}"/>
67 67 </div>
68 68 <div title="${cs.author}" class="user">${h.shorter(h.person(cs.author),22)}</div>
69 69 </div>
70 70 <div class="date">${h.fmt_date(cs.date)}</div>
71 71 </div>
72 72 <div class="mid">
73 73 <div class="message">${h.urlify_commit(cs.message, c.repo_name,h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
74 74 <div class="expand"><span class="expandtext">&darr; ${_('show more')} &darr;</span></div>
75 75 </div>
76 76 <div class="right">
77 77 <div class="changes">
78 78 <div id="changed_total_${cs.raw_id}" style="float:right;" class="changed_total tooltip" title="${h.tooltip(_('Affected number of files, click to show more details'))}">${len(cs.affected_files)}</div>
79 79 <div class="comments-container">
80 80 %if len(c.comments.get(cs.raw_id,[])) > 0:
81 81 <div class="comments-cnt" title="${('comments')}">
82 82 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
83 83 <div class="comments-cnt">${len(c.comments[cs.raw_id])}</div>
84 84 <img src="${h.url('/images/icons/comments.png')}">
85 85 </a>
86 86 </div>
87 87 %endif
88 88 </div>
89 89 <div class="changeset-status-container">
90 90 %if c.statuses.get(cs.raw_id):
91 91 <div title="${_('Changeset status')}" class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
92 92 <div class="changeset-status-ico">
93 93 %if c.statuses.get(cs.raw_id)[2]:
94 94 <a class="tooltip" title="${_('Click to open associated pull request')}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" /></a>
95 95 %else:
96 96 <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
97 97 %endif
98 98 </div>
99 99 %endif
100 100 </div>
101 101 </div>
102 102 %if cs.parents:
103 103 %for p_cs in reversed(cs.parents):
104 104 <div class="parent">${_('Parent')}
105 105 <span class="changeset_id">${p_cs.revision}:<span class="changeset_hash">${h.link_to(h.short_id(p_cs.raw_id),
106 106 h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}</span></span>
107 107 </div>
108 108 %endfor
109 109 %else:
110 110 <div class="parent">${_('No parents')}</div>
111 111 %endif
112 112
113 113 <span class="logtags">
114 114 %if len(cs.parents)>1:
115 115 <span class="merge">${_('merge')}</span>
116 116 %endif
117 117 %if cs.branch:
118 118 <span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
119 119 ${h.link_to(h.shorter(cs.branch),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
120 120 </span>
121 121 %endif
122 122 %if h.is_hg(c.rhodecode_repo):
123 123 %for book in cs.bookmarks:
124 124 <span class="bookbook" title="${'%s %s' % (_('bookmark'),book)}">
125 125 ${h.link_to(h.shorter(book),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}
126 126 </span>
127 127 %endfor
128 128 %endif
129 129 %for tag in cs.tags:
130 130 <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
131 131 ${h.link_to(h.shorter(tag),h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
132 132 %endfor
133 133 </span>
134 134 </div>
135 135 </div>
136 136
137 137 %endfor
138 138 <div class="pagination-wh pagination-left">
139 139 ${c.pagination.pager('$link_previous ~2~ $link_next')}
140 140 </div>
141 141 </div>
142 142 </div>
143 143
144 144 <script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
145 145 <script type="text/javascript">
146 146 YAHOO.util.Event.onDOMReady(function(){
147 147
148 148 //Monitor range checkboxes and build a link to changesets
149 149 //ranges
150 150 var checkboxes = YUD.getElementsByClassName('changeset_range');
151 151 var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
152 152 YUE.on(checkboxes,'click',function(e){
153 153 var clicked_cb = e.currentTarget;
154 154 var checked_checkboxes = [];
155 155 for (pos in checkboxes){
156 156 if(checkboxes[pos].checked){
157 157 checked_checkboxes.push(checkboxes[pos]);
158 158 }
159 159 }
160 160 if(YUD.get('open_new_pr')){
161 161 if(checked_checkboxes.length>0){
162 162 // modify open pull request to show we have selected cs
163 163 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
164 164
165 165 }else{
166 166 YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
167 167 }
168 168 }
169 169
170 if(checked_checkboxes.length>1){
170 if(checked_checkboxes.length>0){
171 171 var rev_end = checked_checkboxes[0].name;
172 172 var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
173 173
174 174 // now select all checkboxes in the middle.
175 175 var checked = false;
176 176 for (var i=0; i<checkboxes.length; i++){
177 177 var cb = checkboxes[i];
178 178 var rev = cb.name;
179 179
180 180 if (rev == rev_end){
181 181 checked = true;
182 182 }
183 183 if (checked){
184 184 cb.checked = true;
185 185 }
186 186 else{
187 187 cb.checked = false;
188 188 }
189 189 if (rev == rev_start){
190 190 checked = false;
191 191 }
192 192
193 193 }
194 194
195 195 var url = url_tmpl.replace('__REVRANGE__',
196 196 rev_start+'...'+rev_end);
197 197
198 198 var link = _TM['Show selected changes __S -> __E'];
199 199 link = link.replace('__S',rev_start.substr(0,6));
200 200 link = link.replace('__E',rev_end.substr(0,6));
201 201 YUD.get('rev_range_container').href = url;
202 202 YUD.get('rev_range_container').innerHTML = link;
203 203 YUD.setStyle('rev_range_container','display','');
204 204 YUD.setStyle('rev_range_clear','display','');
205 205
206 206 YUD.get('open_new_pr').href += '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
207 207
208 208 }
209 209 else{
210 210 YUD.setStyle('rev_range_container','display','none');
211 211 YUD.setStyle('rev_range_clear','display','none');
212 212 }
213 213 });
214 214 YUE.on('rev_range_clear','click',function(e){
215 215 for (var i=0; i<checkboxes.length; i++){
216 216 var cb = checkboxes[i];
217 217 cb.checked = false;
218 218 }
219 219 YUE.preventDefault(e);
220 220 })
221 221 var msgs = YUQ('.message');
222 222 // get first element height
223 223 var el = YUQ('#graph_content .container')[0];
224 224 var row_h = el.clientHeight;
225 225 for(var i=0;i<msgs.length;i++){
226 226 var m = msgs[i];
227 227
228 228 var h = m.clientHeight;
229 229 var pad = YUD.getStyle(m,'padding');
230 230 if(h > row_h){
231 231 var offset = row_h - (h+12);
232 232 YUD.setStyle(m.nextElementSibling,'display','block');
233 233 YUD.setStyle(m.nextElementSibling,'margin-top',offset+'px');
234 234 };
235 235 }
236 236 YUE.on(YUQ('.expand'),'click',function(e){
237 237 var elem = e.currentTarget.parentNode.parentNode;
238 238 YUD.setStyle(e.currentTarget,'display','none');
239 239 YUD.setStyle(elem,'height','auto');
240 240
241 241 //redraw the graph, line_count and jsdata are global vars
242 242 set_canvas(100);
243 243
244 244 var r = new BranchRenderer();
245 245 r.render(jsdata,100,line_count);
246 246
247 247 })
248 248
249 249 // Fetch changeset details
250 250 YUE.on(YUD.getElementsByClassName('changed_total'),'click',function(e){
251 251 var id = e.currentTarget.id;
252 252 var url = "${h.url('changelog_details',repo_name=c.repo_name,cs='__CS__')}";
253 253 var url = url.replace('__CS__',id.replace('changed_total_',''));
254 254 ypjax(url,id,function(){tooltip_activate()});
255 255 });
256 256
257 257 // change branch filter
258 258 YUE.on(YUD.get('branch_filter'),'change',function(e){
259 259 var selected_branch = e.currentTarget.options[e.currentTarget.selectedIndex].value;
260 260 var url_main = "${h.url('changelog_home',repo_name=c.repo_name)}";
261 261 var url = "${h.url('changelog_home',repo_name=c.repo_name,branch='__BRANCH__')}";
262 262 var url = url.replace('__BRANCH__',selected_branch);
263 263 if(selected_branch != ''){
264 264 window.location = url;
265 265 }else{
266 266 window.location = url_main;
267 267 }
268 268
269 269 });
270 270
271 271 function set_canvas(width) {
272 272 var c = document.getElementById('graph_nodes');
273 273 var t = document.getElementById('graph_content');
274 274 canvas = document.getElementById('graph_canvas');
275 275 var div_h = t.clientHeight;
276 276 c.style.height=div_h+'px';
277 277 canvas.setAttribute('height',div_h);
278 278 c.style.height=width+'px';
279 279 canvas.setAttribute('width',width);
280 280 };
281 281 var heads = 1;
282 282 var line_count = 0;
283 283 var jsdata = ${c.jsdata|n};
284 284
285 285 for (var i=0;i<jsdata.length;i++) {
286 286 var in_l = jsdata[i][2];
287 287 for (var j in in_l) {
288 288 var m = in_l[j][1];
289 289 if (m > line_count)
290 290 line_count = m;
291 291 }
292 292 }
293 293 set_canvas(100);
294 294
295 295 var r = new BranchRenderer();
296 296 r.render(jsdata,100,line_count);
297 297
298 298 });
299 299 </script>
300 300 %else:
301 301 ${_('There are no changes yet')}
302 302 %endif
303 303 </div>
304 304 </div>
305 305 </%def>
General Comments 0
You need to be logged in to leave comments. Login now