##// END OF EJS Templates
small fixes for git support
marcink -
r1281:0d3706cc beta
parent child Browse files
Show More
@@ -1,104 +1,111
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.changelog
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 changelog controller for rhodecode
7 7
8 8 :created_on: Apr 21, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 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
28 28 try:
29 29 import json
30 30 except ImportError:
31 31 #python 2.5 compatibility
32 32 import simplejson as json
33 33
34 34 from mercurial.graphmod import colored, CHANGESET, revisions as graph_rev
35 35 from pylons import request, session, tmpl_context as c
36 36
37 37 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
38 38 from rhodecode.lib.base import BaseRepoController, render
39 39 from rhodecode.lib.helpers import RepoPage
40 40
41 41 log = logging.getLogger(__name__)
42 42
43 43
44 44 class ChangelogController(BaseRepoController):
45 45
46 46 @LoginRequired()
47 47 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
48 48 'repository.admin')
49 49 def __before__(self):
50 50 super(ChangelogController, self).__before__()
51 51 c.affected_files_cut_off = 60
52 52
53 53 def index(self):
54 54 limit = 100
55 55 default = 20
56 56 if request.params.get('size'):
57 57 try:
58 58 int_size = int(request.params.get('size'))
59 59 except ValueError:
60 60 int_size = default
61 61 int_size = int_size if int_size <= limit else limit
62 62 c.size = int_size
63 63 session['changelog_size'] = c.size
64 64 session.save()
65 65 else:
66 66 c.size = int(session.get('changelog_size', default))
67 67
68 68 p = int(request.params.get('page', 1))
69 69 branch_name = request.params.get('branch', None)
70 70 c.total_cs = len(c.rhodecode_repo)
71 71 c.pagination = RepoPage(c.rhodecode_repo, page=p,
72 72 item_count=c.total_cs, items_per_page=c.size,
73 73 branch_name=branch_name)
74 74
75 75 self._graph(c.rhodecode_repo, c.total_cs, c.size, p)
76 76
77 77 return render('changelog/changelog.html')
78 78
79 79 def _graph(self, repo, repo_size, size, p):
80 80 """
81 81 Generates a DAG graph for mercurial
82 82
83 83 :param repo: repo instance
84 84 :param size: number of commits to show
85 85 :param p: page number
86 86 """
87 if not repo.revisions or repo.alias == 'git':
87 if not repo.revisions:
88 88 c.jsdata = json.dumps([])
89 89 return
90 90
91 91 revcount = min(repo_size, size)
92 92 offset = 1 if p == 1 else ((p - 1) * revcount + 1)
93 93 rev_start = repo.revisions.index(repo.revisions[(-1 * offset)])
94 94 rev_end = max(0, rev_start - revcount)
95 95
96 data = []
97 if repo.alias == 'git':
98 for _ in xrange(rev_end, rev_start):
99 vtx = [0, 1]
100 edges = [[0, 0, 1]]
101 data.append(['', vtx, edges])
102
103 elif repo.alias == 'hg':
96 104 dag = graph_rev(repo._repo, rev_start, rev_end)
97 105 c.dag = tree = list(colored(dag))
98 data = []
99 106 for (id, type, ctx, vtx, edges) in tree:
100 107 if type != CHANGESET:
101 108 continue
102 data.append(('', vtx, edges))
109 data.append(['', vtx, edges])
103 110
104 111 c.jsdata = json.dumps(data)
@@ -1,187 +1,187
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.summary
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Summary controller for Rhodecode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 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 calendar
27 27 import logging
28 28 from time import mktime
29 29 from datetime import datetime, timedelta, date
30 30
31 31 from vcs.exceptions import ChangesetError
32 32
33 33 from pylons import tmpl_context as c, request, url
34 34 from pylons.i18n.translation import _
35 35
36 36 from rhodecode.model.db import Statistics, Repository
37 37 from rhodecode.model.repo import RepoModel
38 38
39 39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
40 40 from rhodecode.lib.base import BaseRepoController, render
41 41 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
42 42
43 43 from rhodecode.lib.celerylib import run_task
44 44 from rhodecode.lib.celerylib.tasks import get_commits_stats, \
45 45 LANGUAGES_EXTENSIONS_MAP
46 46 from rhodecode.lib.helpers import RepoPage
47 47
48 48 try:
49 49 import json
50 50 except ImportError:
51 51 #python 2.5 compatibility
52 52 import simplejson as json
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class SummaryController(BaseRepoController):
57 57
58 58 @LoginRequired()
59 59 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
60 60 'repository.admin')
61 61 def __before__(self):
62 62 super(SummaryController, self).__before__()
63 63
64 64 def index(self, repo_name):
65 65
66 66 e = request.environ
67 67 c.dbrepo = dbrepo = Repository.by_repo_name(repo_name)
68 68
69 69 c.following = self.scm_model.is_following_repo(repo_name,
70 70 self.rhodecode_user.user_id)
71 71
72 72 def url_generator(**kw):
73 73 return url('shortlog_home', repo_name=repo_name, size=10, **kw)
74 74
75 75 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
76 76 items_per_page=10, url=url_generator)
77 77
78 78 if self.rhodecode_user.username == 'default':
79 79 #for default(anonymous) user we don't need to pass credentials
80 80 username = ''
81 81 password = ''
82 82 else:
83 83 username = str(self.rhodecode_user.username)
84 84 password = '@'
85 85
86 86 if e.get('wsgi.url_scheme') == 'https':
87 87 split_s = 'https://'
88 88 else:
89 89 split_s = 'http://'
90 90
91 91 qualified_uri = [split_s] + [url.current(qualified=True)\
92 92 .split(split_s)[-1]]
93 93 uri = u'%(proto)s%(user)s%(pass)s%(rest)s' \
94 94 % {'user': username,
95 95 'pass': password,
96 96 'proto': qualified_uri[0],
97 97 'rest': qualified_uri[1]}
98 98 c.clone_repo_url = uri
99 99 c.repo_tags = OrderedDict()
100 100 for name, hash in c.rhodecode_repo.tags.items()[:10]:
101 101 try:
102 102 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
103 103 except ChangesetError:
104 104 c.repo_tags[name] = EmptyChangeset(hash)
105 105
106 106 c.repo_branches = OrderedDict()
107 107 for name, hash in c.rhodecode_repo.branches.items()[:10]:
108 108 try:
109 109 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
110 110 except ChangesetError:
111 111 c.repo_branches[name] = EmptyChangeset(hash)
112 112
113 113 td = date.today() + timedelta(days=1)
114 114 td_1m = td - timedelta(days=calendar.mdays[td.month])
115 115 td_1y = td - timedelta(days=365)
116 116
117 117 ts_min_m = mktime(td_1m.timetuple())
118 118 ts_min_y = mktime(td_1y.timetuple())
119 119 ts_max_y = mktime(td.timetuple())
120 120
121 121 if dbrepo.enable_statistics:
122 122 c.no_data_msg = _('No data loaded yet')
123 123 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
124 124 else:
125 125 c.no_data_msg = _('Statistics are disabled for this repository')
126 126 c.ts_min = ts_min_m
127 127 c.ts_max = ts_max_y
128 128
129 129 stats = self.sa.query(Statistics)\
130 130 .filter(Statistics.repository == dbrepo)\
131 131 .scalar()
132 132
133 133 c.stats_percentage = 0
134 134
135 135 if stats and stats.languages:
136 136 c.no_data = False is dbrepo.enable_statistics
137 lang_stats = json.loads(stats.languages)
137 lang_stats_d = json.loads(stats.languages)
138 138 c.commit_data = stats.commit_activity
139 139 c.overview_data = stats.commit_activity_combined
140 140
141 141 lang_stats = [(x, {"count": y,
142 142 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
143 for x, y in lang_stats.items()]
143 for x, y in lang_stats_d.items()]
144 144
145 145 c.trending_languages = json.dumps(OrderedDict(
146 146 sorted(lang_stats, reverse=True,
147 147 key=lambda k: k[1])[:10]
148 148 )
149 149 )
150 150 last_rev = stats.stat_on_revision
151 151 c.repo_last_rev = c.rhodecode_repo.count() - 1 \
152 152 if c.rhodecode_repo.revisions else 0
153 153 if last_rev == 0 or c.repo_last_rev == 0:
154 154 pass
155 155 else:
156 156 c.stats_percentage = '%.2f' % ((float((last_rev)) /
157 157 c.repo_last_rev) * 100)
158 158 else:
159 159 c.commit_data = json.dumps({})
160 160 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
161 161 c.trending_languages = json.dumps({})
162 162 c.no_data = True
163 163
164 164 c.enable_downloads = dbrepo.enable_downloads
165 165 if c.enable_downloads:
166 166 c.download_options = self._get_download_links(c.rhodecode_repo)
167 167
168 168 return render('summary/summary.html')
169 169
170 170 def _get_download_links(self, repo):
171 171
172 172 download_l = []
173 173
174 174 branches_group = ([], _("Branches"))
175 175 tags_group = ([], _("Tags"))
176 176
177 177 for name, chs in c.rhodecode_repo.branches.items():
178 178 #chs = chs.split(':')[-1]
179 179 branches_group[0].append((chs, name),)
180 180 download_l.append(branches_group)
181 181
182 182 for name, chs in c.rhodecode_repo.tags.items():
183 183 #chs = chs.split(':')[-1]
184 184 tags_group[0].append((chs, name),)
185 185 download_l.append(tags_group)
186 186
187 187 return download_l
@@ -1,704 +1,704
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
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.dbrepo.just_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 <div class="box box-left">
21 21 <!-- box / title -->
22 22 <div class="title">
23 23 ${self.breadcrumbs()}
24 24 </div>
25 25 <!-- end box / title -->
26 26 <div class="form">
27 27 <div class="fields">
28 28
29 29 <div class="field">
30 30 <div class="label">
31 31 <label>${_('Name')}:</label>
32 32 </div>
33 33 <div class="input-short">
34 34 %if c.rhodecode_user.username != 'default':
35 35 %if c.following:
36 36 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
37 37 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
38 38 </span>
39 39 %else:
40 40 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
41 41 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
42 42 </span>
43 43 %endif
44 44 %endif:
45 45
46 46 ##REPO TYPE
47 47 %if c.dbrepo.repo_type =='hg':
48 48 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
49 49 %endif
50 50 %if c.dbrepo.repo_type =='git':
51 51 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
52 52 %endif
53 53
54 54 ##PUBLIC/PRIVATE
55 55 %if c.dbrepo.private:
56 56 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url("/images/icons/lock.png")}"/>
57 57 %else:
58 58 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url("/images/icons/lock_open.png")}"/>
59 59 %endif
60 60
61 61 ##REPO NAME
62 62 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;clear:right">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
63 63
64 64 ##FORK
65 65 %if c.dbrepo.fork:
66 66 <div style="margin-top:5px;clear:both"">
67 67 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
68 68 <img class="icon" alt="${_('public')}"
69 69 title="${_('Fork of')} ${c.dbrepo.fork.repo_name}"
70 70 src="${h.url("/images/icons/arrow_divide.png")}"/>
71 71 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
72 72 </a>
73 73 </div>
74 74 %endif
75 75 ##REMOTE
76 76 %if c.dbrepo.clone_uri:
77 77 <div style="margin-top:5px;clear:both">
78 78 <a href="${h.url(str(c.dbrepo.clone_uri))}">
79 79 <img class="icon" alt="${_('remote clone')}"
80 80 title="${_('Clone from')} ${c.dbrepo.clone_uri}"
81 81 src="${h.url("/images/icons/connect.png")}"/>
82 82 ${_('Clone from')} ${c.dbrepo.clone_uri}
83 83 </a>
84 84 </div>
85 85 %endif
86 86 </div>
87 87 </div>
88 88
89 89
90 90 <div class="field">
91 91 <div class="label">
92 92 <label>${_('Description')}:</label>
93 93 </div>
94 94 <div class="input-short">
95 95 ${c.dbrepo.description}
96 96 </div>
97 97 </div>
98 98
99 99
100 100 <div class="field">
101 101 <div class="label">
102 102 <label>${_('Contact')}:</label>
103 103 </div>
104 104 <div class="input-short">
105 105 <div class="gravatar">
106 106 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
107 107 </div>
108 108 ${_('Username')}: ${c.dbrepo.user.username}<br/>
109 109 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
110 110 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
111 111 </div>
112 112 </div>
113 113
114 114 <div class="field">
115 115 <div class="label">
116 116 <label>${_('Last change')}:</label>
117 117 </div>
118 118 <div class="input-short">
119 119 <b>${'r%s:%s' % (h.get_changeset_safe(c.rhodecode_repo,'tip').revision,
120 120 h.get_changeset_safe(c.rhodecode_repo,'tip').short_id)}</b> -
121 121 <span class="tooltip" title="${c.rhodecode_repo.last_change}">
122 122 ${h.age(c.rhodecode_repo.last_change)}</span><br/>
123 123 ${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author}
124 124
125 125 </div>
126 126 </div>
127 127
128 128 <div class="field">
129 129 <div class="label">
130 130 <label>${_('Clone url')}:</label>
131 131 </div>
132 132 <div class="input-short">
133 <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
133 <input type="text" id="clone_url" readonly="readonly" value="${c.rhodecode_repo.alias} clone ${c.clone_repo_url}" size="70"/>
134 134 </div>
135 135 </div>
136 136
137 137 <div class="field">
138 138 <div class="label">
139 139 <label>${_('Trending source files')}:</label>
140 140 </div>
141 141 <div class="input-short">
142 142 <div id="lang_stats"></div>
143 143 </div>
144 144 </div>
145 145
146 146 <div class="field">
147 147 <div class="label">
148 148 <label>${_('Download')}:</label>
149 149 </div>
150 150 <div class="input-short">
151 151 %if len(c.rhodecode_repo.revisions) == 0:
152 152 ${_('There are no downloads yet')}
153 153 %elif c.enable_downloads is False:
154 154 ${_('Downloads are disabled for this repository')}
155 155 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
156 156 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
157 157 %endif
158 158 %else:
159 159 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
160 160 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
161 161 %if cnt >=1:
162 162 |
163 163 %endif
164 164 <span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
165 165 id="${archive['type']+'_link'}">${h.link_to(archive['type'],
166 166 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
167 167 fname='tip'+archive['extension']),class_="archive_icon")}</span>
168 168 %endfor
169 169 %endif
170 170 </div>
171 171 </div>
172 172
173 173 <div class="field">
174 174 <div class="label">
175 175 <label>${_('Feeds')}:</label>
176 176 </div>
177 177 <div class="input-short">
178 178 %if c.rhodecode_user.username != 'default':
179 179 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
180 180 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
181 181 %else:
182 182 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
183 183 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
184 184 %endif
185 185 </div>
186 186 </div>
187 187 </div>
188 188 </div>
189 189 <script type="text/javascript">
190 190 YUE.onDOMReady(function(e){
191 191 id = 'clone_url';
192 192 YUE.on(id,'click',function(e){
193 193 YUD.get('clone_url').select();
194 194 })
195 195 })
196 196 var data = ${c.trending_languages|n};
197 197 var total = 0;
198 198 var no_data = true;
199 199 for (k in data){
200 200 total += data[k].count;
201 201 no_data = false;
202 202 }
203 203 var tbl = document.createElement('table');
204 204 tbl.setAttribute('class','trending_language_tbl');
205 205 var cnt = 0;
206 206 for (k in data){
207 207 cnt += 1;
208 208 var hide = cnt>2;
209 209 var tr = document.createElement('tr');
210 210 if (hide){
211 211 tr.setAttribute('style','display:none');
212 212 tr.setAttribute('class','stats_hidden');
213 213 }
214 214 var percentage = Math.round((data[k].count/total*100),2);
215 215 var value = data[k].count;
216 216 var td1 = document.createElement('td');
217 217 td1.width = 150;
218 218 var trending_language_label = document.createElement('div');
219 219 trending_language_label.innerHTML = data[k].desc+" ("+k+")";
220 220 td1.appendChild(trending_language_label);
221 221
222 222 var td2 = document.createElement('td');
223 223 td2.setAttribute('style','padding-right:14px !important');
224 224 var trending_language = document.createElement('div');
225 225 var nr_files = value+" ${_('files')}";
226 226
227 227 trending_language.title = k+" "+nr_files;
228 228
229 229 if (percentage>22){
230 230 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
231 231 }
232 232 else{
233 233 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
234 234 }
235 235
236 236 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
237 237 trending_language.style.width=percentage+"%";
238 238 td2.appendChild(trending_language);
239 239
240 240 tr.appendChild(td1);
241 241 tr.appendChild(td2);
242 242 tbl.appendChild(tr);
243 243 if(cnt == 2){
244 244 var show_more = document.createElement('tr');
245 245 var td=document.createElement('td');
246 246 lnk = document.createElement('a');
247 247 lnk.href='#';
248 248 lnk.innerHTML = "${_('show more')}";
249 249 lnk.id='code_stats_show_more';
250 250 td.appendChild(lnk);
251 251 show_more.appendChild(td);
252 252 show_more.appendChild(document.createElement('td'));
253 253 tbl.appendChild(show_more);
254 254 }
255 255
256 256 }
257 257 if(no_data){
258 258 var tr = document.createElement('tr');
259 259 var td1 = document.createElement('td');
260 260 td1.innerHTML = "${c.no_data_msg}";
261 261 tr.appendChild(td1);
262 262 tbl.appendChild(tr);
263 263 }
264 264 YUD.get('lang_stats').appendChild(tbl);
265 265 YUE.on('code_stats_show_more','click',function(){
266 266 l = YUD.getElementsByClassName('stats_hidden')
267 267 for (e in l){
268 268 YUD.setStyle(l[e],'display','');
269 269 };
270 270 YUD.setStyle(YUD.get('code_stats_show_more'),
271 271 'display','none');
272 272 })
273 273
274 274
275 275 YUE.on('download_options','change',function(e){
276 276 var new_cs = e.target.options[e.target.selectedIndex];
277 277 var tmpl_links = {}
278 278 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
279 279 tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
280 280 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
281 281 fname='__CS__'+archive['extension']),class_="archive_icon")}';
282 282 %endfor
283 283
284 284
285 285 for(k in tmpl_links){
286 286 var s = YUD.get(k+'_link')
287 287 title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
288 288 s.title = title_tmpl.replace('__CS_NAME__',new_cs.text);
289 289 s.title = s.title.replace('__CS_EXT__',k);
290 290 s.innerHTML = tmpl_links[k].replace('__CS__',new_cs.value);
291 291 }
292 292
293 293 })
294 294
295 295 </script>
296 296 </div>
297 297
298 298 <div class="box box-right" style="min-height:455px">
299 299 <!-- box / title -->
300 300 <div class="title">
301 301 <h5>${_('Commit activity by day / author')}</h5>
302 302 </div>
303 303
304 304 <div class="graph">
305 305 <div style="padding:0 10px 10px 15px;font-size: 1.2em;">
306 306 %if c.no_data:
307 307 ${c.no_data_msg}
308 308 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
309 309 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
310 310 %endif
311 311
312 312 %else:
313 313 ${_('Loaded in')} ${c.stats_percentage} %
314 314 %endif
315 315 </div>
316 316 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
317 317 <div style="clear: both;height: 10px"></div>
318 318 <div id="overview" style="width:450px;height:100px;float:left"></div>
319 319
320 320 <div id="legend_data" style="clear:both;margin-top:10px;">
321 321 <div id="legend_container"></div>
322 322 <div id="legend_choices">
323 323 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
324 324 </div>
325 325 </div>
326 326 <script type="text/javascript">
327 327 /**
328 328 * Plots summary graph
329 329 *
330 330 * @class SummaryPlot
331 331 * @param {from} initial from for detailed graph
332 332 * @param {to} initial to for detailed graph
333 333 * @param {dataset}
334 334 * @param {overview_dataset}
335 335 */
336 336 function SummaryPlot(from,to,dataset,overview_dataset) {
337 337 var initial_ranges = {
338 338 "xaxis":{
339 339 "from":from,
340 340 "to":to,
341 341 },
342 342 };
343 343 var dataset = dataset;
344 344 var overview_dataset = [overview_dataset];
345 345 var choiceContainer = YUD.get("legend_choices");
346 346 var choiceContainerTable = YUD.get("legend_choices_tables");
347 347 var plotContainer = YUD.get('commit_history');
348 348 var overviewContainer = YUD.get('overview');
349 349
350 350 var plot_options = {
351 351 bars: {show:true,align:'center',lineWidth:4},
352 352 legend: {show:true, container:"legend_container"},
353 353 points: {show:true,radius:0,fill:false},
354 354 yaxis: {tickDecimals:0,},
355 355 xaxis: {
356 356 mode: "time",
357 357 timeformat: "%d/%m",
358 358 min:from,
359 359 max:to,
360 360 },
361 361 grid: {
362 362 hoverable: true,
363 363 clickable: true,
364 364 autoHighlight:true,
365 365 color: "#999"
366 366 },
367 367 //selection: {mode: "x"}
368 368 };
369 369 var overview_options = {
370 370 legend:{show:false},
371 371 bars: {show:true,barWidth: 2,},
372 372 shadowSize: 0,
373 373 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
374 374 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
375 375 grid: {color: "#999",},
376 376 selection: {mode: "x"}
377 377 };
378 378
379 379 /**
380 380 *get dummy data needed in few places
381 381 */
382 382 function getDummyData(label){
383 383 return {"label":label,
384 384 "data":[{"time":0,
385 385 "commits":0,
386 386 "added":0,
387 387 "changed":0,
388 388 "removed":0,
389 389 }],
390 390 "schema":["commits"],
391 391 "color":'#ffffff',
392 392 }
393 393 }
394 394
395 395 /**
396 396 * generate checkboxes accordindly to data
397 397 * @param keys
398 398 * @returns
399 399 */
400 400 function generateCheckboxes(data) {
401 401 //append checkboxes
402 402 var i = 0;
403 403 choiceContainerTable.innerHTML = '';
404 404 for(var pos in data) {
405 405
406 406 data[pos].color = i;
407 407 i++;
408 408 if(data[pos].label != ''){
409 409 choiceContainerTable.innerHTML += '<tr><td>'+
410 410 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
411 411 +data[pos].label+
412 412 '</td></tr>';
413 413 }
414 414 }
415 415 }
416 416
417 417 /**
418 418 * ToolTip show
419 419 */
420 420 function showTooltip(x, y, contents) {
421 421 var div=document.getElementById('tooltip');
422 422 if(!div) {
423 423 div = document.createElement('div');
424 424 div.id="tooltip";
425 425 div.style.position="absolute";
426 426 div.style.border='1px solid #fdd';
427 427 div.style.padding='2px';
428 428 div.style.backgroundColor='#fee';
429 429 document.body.appendChild(div);
430 430 }
431 431 YUD.setStyle(div, 'opacity', 0);
432 432 div.innerHTML = contents;
433 433 div.style.top=(y + 5) + "px";
434 434 div.style.left=(x + 5) + "px";
435 435
436 436 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
437 437 anim.animate();
438 438 }
439 439
440 440 /**
441 441 * This function will detect if selected period has some changesets
442 442 for this user if it does this data is then pushed for displaying
443 443 Additionally it will only display users that are selected by the checkbox
444 444 */
445 445 function getDataAccordingToRanges(ranges) {
446 446
447 447 var data = [];
448 448 var keys = [];
449 449 for(var key in dataset){
450 450 var push = false;
451 451
452 452 //method1 slow !!
453 453 //*
454 454 for(var ds in dataset[key].data){
455 455 commit_data = dataset[key].data[ds];
456 456 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
457 457 push = true;
458 458 break;
459 459 }
460 460 }
461 461 //*/
462 462
463 463 /*//method2 sorted commit data !!!
464 464
465 465 var first_commit = dataset[key].data[0].time;
466 466 var last_commit = dataset[key].data[dataset[key].data.length-1].time;
467 467
468 468 if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
469 469 push = true;
470 470 }
471 471 //*/
472 472
473 473 if(push){
474 474 data.push(dataset[key]);
475 475 }
476 476 }
477 477 if(data.length >= 1){
478 478 return data;
479 479 }
480 480 else{
481 481 //just return dummy data for graph to plot itself
482 482 return [getDummyData('')];
483 483 }
484 484
485 485 }
486 486
487 487 /**
488 488 * redraw using new checkbox data
489 489 */
490 490 function plotchoiced(e,args){
491 491 var cur_data = args[0];
492 492 var cur_ranges = args[1];
493 493
494 494 var new_data = [];
495 495 var inputs = choiceContainer.getElementsByTagName("input");
496 496
497 497 //show only checked labels
498 498 for(var i=0; i<inputs.length; i++) {
499 499 var checkbox_key = inputs[i].name;
500 500
501 501 if(inputs[i].checked){
502 502 for(var d in cur_data){
503 503 if(cur_data[d].label == checkbox_key){
504 504 new_data.push(cur_data[d]);
505 505 }
506 506 }
507 507 }
508 508 else{
509 509 //push dummy data to not hide the label
510 510 new_data.push(getDummyData(checkbox_key));
511 511 }
512 512 }
513 513
514 514 var new_options = YAHOO.lang.merge(plot_options, {
515 515 xaxis: {
516 516 min: cur_ranges.xaxis.from,
517 517 max: cur_ranges.xaxis.to,
518 518 mode:"time",
519 519 timeformat: "%d/%m",
520 520 },
521 521 });
522 522 if (!new_data){
523 523 new_data = [[0,1]];
524 524 }
525 525 // do the zooming
526 526 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
527 527
528 528 plot.subscribe("plotselected", plotselected);
529 529
530 530 //resubscribe plothover
531 531 plot.subscribe("plothover", plothover);
532 532
533 533 // don't fire event on the overview to prevent eternal loop
534 534 overview.setSelection(cur_ranges, true);
535 535
536 536 }
537 537
538 538 /**
539 539 * plot only selected items from overview
540 540 * @param ranges
541 541 * @returns
542 542 */
543 543 function plotselected(ranges,cur_data) {
544 544 //updates the data for new plot
545 545 data = getDataAccordingToRanges(ranges);
546 546 generateCheckboxes(data);
547 547
548 548 var new_options = YAHOO.lang.merge(plot_options, {
549 549 xaxis: {
550 550 min: ranges.xaxis.from,
551 551 max: ranges.xaxis.to,
552 552 mode:"time",
553 553 timeformat: "%d/%m",
554 554 },
555 555 yaxis: {
556 556 min: ranges.yaxis.from,
557 557 max: ranges.yaxis.to,
558 558 },
559 559
560 560 });
561 561 // do the zooming
562 562 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
563 563
564 564 plot.subscribe("plotselected", plotselected);
565 565
566 566 //resubscribe plothover
567 567 plot.subscribe("plothover", plothover);
568 568
569 569 // don't fire event on the overview to prevent eternal loop
570 570 overview.setSelection(ranges, true);
571 571
572 572 //resubscribe choiced
573 573 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
574 574 }
575 575
576 576 var previousPoint = null;
577 577
578 578 function plothover(o) {
579 579 var pos = o.pos;
580 580 var item = o.item;
581 581
582 582 //YUD.get("x").innerHTML = pos.x.toFixed(2);
583 583 //YUD.get("y").innerHTML = pos.y.toFixed(2);
584 584 if (item) {
585 585 if (previousPoint != item.datapoint) {
586 586 previousPoint = item.datapoint;
587 587
588 588 var tooltip = YUD.get("tooltip");
589 589 if(tooltip) {
590 590 tooltip.parentNode.removeChild(tooltip);
591 591 }
592 592 var x = item.datapoint.x.toFixed(2);
593 593 var y = item.datapoint.y.toFixed(2);
594 594
595 595 if (!item.series.label){
596 596 item.series.label = 'commits';
597 597 }
598 598 var d = new Date(x*1000);
599 599 var fd = d.toDateString()
600 600 var nr_commits = parseInt(y);
601 601
602 602 var cur_data = dataset[item.series.label].data[item.dataIndex];
603 603 var added = cur_data.added;
604 604 var changed = cur_data.changed;
605 605 var removed = cur_data.removed;
606 606
607 607 var nr_commits_suffix = " ${_('commits')} ";
608 608 var added_suffix = " ${_('files added')} ";
609 609 var changed_suffix = " ${_('files changed')} ";
610 610 var removed_suffix = " ${_('files removed')} ";
611 611
612 612
613 613 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
614 614 if(added==1){added_suffix=" ${_('file added')} ";}
615 615 if(changed==1){changed_suffix=" ${_('file changed')} ";}
616 616 if(removed==1){removed_suffix=" ${_('file removed')} ";}
617 617
618 618 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
619 619 +'<br/>'+
620 620 nr_commits + nr_commits_suffix+'<br/>'+
621 621 added + added_suffix +'<br/>'+
622 622 changed + changed_suffix + '<br/>'+
623 623 removed + removed_suffix + '<br/>');
624 624 }
625 625 }
626 626 else {
627 627 var tooltip = YUD.get("tooltip");
628 628
629 629 if(tooltip) {
630 630 tooltip.parentNode.removeChild(tooltip);
631 631 }
632 632 previousPoint = null;
633 633 }
634 634 }
635 635
636 636 /**
637 637 * MAIN EXECUTION
638 638 */
639 639
640 640 var data = getDataAccordingToRanges(initial_ranges);
641 641 generateCheckboxes(data);
642 642
643 643 //main plot
644 644 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
645 645
646 646 //overview
647 647 var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
648 648
649 649 //show initial selection on overview
650 650 overview.setSelection(initial_ranges);
651 651
652 652 plot.subscribe("plotselected", plotselected);
653 653
654 654 overview.subscribe("plotselected", function (ranges) {
655 655 plot.setSelection(ranges);
656 656 });
657 657
658 658 plot.subscribe("plothover", plothover);
659 659
660 660 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
661 661 }
662 662 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
663 663 </script>
664 664
665 665 </div>
666 666 </div>
667 667
668 668 <div class="box">
669 669 <div class="title">
670 670 <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
671 671 </div>
672 672 <div class="table">
673 673 <div id="shortlog_data">
674 674 <%include file='../shortlog/shortlog_data.html'/>
675 675 </div>
676 676 ##%if c.repo_changesets:
677 677 ## ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
678 678 ##%endif
679 679 </div>
680 680 </div>
681 681 <div class="box">
682 682 <div class="title">
683 683 <div class="breadcrumbs">${h.link_to(_('Tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
684 684 </div>
685 685 <div class="table">
686 686 <%include file='../tags/tags_data.html'/>
687 687 %if c.repo_changesets:
688 688 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
689 689 %endif
690 690 </div>
691 691 </div>
692 692 <div class="box">
693 693 <div class="title">
694 694 <div class="breadcrumbs">${h.link_to(_('Branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
695 695 </div>
696 696 <div class="table">
697 697 <%include file='../branches/branches_data.html'/>
698 698 %if c.repo_changesets:
699 699 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
700 700 %endif
701 701 </div>
702 702 </div>
703 703
704 704 </%def>
General Comments 0
You need to be logged in to leave comments. Login now