##// END OF EJS Templates
added url quote in clone url. fixes issue #809
marcink -
r3635:be78bf3b beta
parent child Browse files
Show More
@@ -1,259 +1,260 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.summary
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Summary controller for Rhodecode
6 Summary controller for Rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import traceback
26 import traceback
27 import calendar
27 import calendar
28 import logging
28 import logging
29 import urllib
29 import urllib
30 from time import mktime
30 from time import mktime
31 from datetime import timedelta, date
31 from datetime import timedelta, date
32 from urlparse import urlparse
32 from urlparse import urlparse
33
33
34 from pylons import tmpl_context as c, request, url, config
34 from pylons import tmpl_context as c, request, url, config
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36 from webob.exc import HTTPBadRequest
36 from webob.exc import HTTPBadRequest
37
37
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39
39
40 from rhodecode.lib import helpers as h
40 from rhodecode.lib.compat import product
41 from rhodecode.lib.compat import product
41 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
42 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
42 NodeDoesNotExistError
43 NodeDoesNotExistError
43 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
44 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
44 from rhodecode.model.db import Statistics, CacheInvalidation
45 from rhodecode.model.db import Statistics, CacheInvalidation
45 from rhodecode.lib.utils import jsonify
46 from rhodecode.lib.utils import jsonify
46 from rhodecode.lib.utils2 import safe_unicode
47 from rhodecode.lib.utils2 import safe_unicode, safe_str
47 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
48 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
48 NotAnonymous
49 NotAnonymous
49 from rhodecode.lib.base import BaseRepoController, render
50 from rhodecode.lib.base import BaseRepoController, render
50 from rhodecode.lib.vcs.backends.base import EmptyChangeset
51 from rhodecode.lib.vcs.backends.base import EmptyChangeset
51 from rhodecode.lib.markup_renderer import MarkupRenderer
52 from rhodecode.lib.markup_renderer import MarkupRenderer
52 from rhodecode.lib.celerylib import run_task
53 from rhodecode.lib.celerylib import run_task
53 from rhodecode.lib.celerylib.tasks import get_commits_stats
54 from rhodecode.lib.celerylib.tasks import get_commits_stats
54 from rhodecode.lib.helpers import RepoPage
55 from rhodecode.lib.helpers import RepoPage
55 from rhodecode.lib.compat import json, OrderedDict
56 from rhodecode.lib.compat import json, OrderedDict
56 from rhodecode.lib.vcs.nodes import FileNode
57 from rhodecode.lib.vcs.nodes import FileNode
57
58
58 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
59
60
60 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
61 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
61 sorted(list(product(ALL_READMES, ALL_EXTS)),
62 sorted(list(product(ALL_READMES, ALL_EXTS)),
62 key=lambda y:y[0][1] + y[1][1])]
63 key=lambda y:y[0][1] + y[1][1])]
63
64
64
65
65 class SummaryController(BaseRepoController):
66 class SummaryController(BaseRepoController):
66
67
67 @LoginRequired()
68 @LoginRequired()
68 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
69 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
69 'repository.admin')
70 'repository.admin')
70 def __before__(self):
71 def __before__(self):
71 super(SummaryController, self).__before__()
72 super(SummaryController, self).__before__()
72
73
73 def index(self, repo_name):
74 def index(self, repo_name):
74 c.dbrepo = dbrepo = c.rhodecode_db_repo
75 c.dbrepo = dbrepo = c.rhodecode_db_repo
75
76
76 def url_generator(**kw):
77 def url_generator(**kw):
77 return url('shortlog_home', repo_name=repo_name, size=10, **kw)
78 return url('shortlog_home', repo_name=repo_name, size=10, **kw)
78
79
79 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
80 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
80 items_per_page=10, url=url_generator)
81 items_per_page=10, url=url_generator)
81 page_revisions = [x.raw_id for x in list(c.repo_changesets)]
82 page_revisions = [x.raw_id for x in list(c.repo_changesets)]
82 c.statuses = c.rhodecode_db_repo.statuses(page_revisions)
83 c.statuses = c.rhodecode_db_repo.statuses(page_revisions)
83
84
84 if self.rhodecode_user.username == 'default':
85 if self.rhodecode_user.username == 'default':
85 # for default(anonymous) user we don't need to pass credentials
86 # for default(anonymous) user we don't need to pass credentials
86 username = ''
87 username = ''
87 password = ''
88 password = ''
88 else:
89 else:
89 username = str(self.rhodecode_user.username)
90 username = str(self.rhodecode_user.username)
90 password = '@'
91 password = '@'
91
92
92 parsed_url = urlparse(url.current(qualified=True))
93 parsed_url = urlparse(url.current(qualified=True))
93
94
94 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
95 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
95
96
96 uri_tmpl = config.get('clone_uri', default_clone_uri)
97 uri_tmpl = config.get('clone_uri', default_clone_uri)
97 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
98 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
98 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
99 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
99 uri_dict = {
100 uri_dict = {
100 'user': urllib.quote(username),
101 'user': urllib.quote(username),
101 'pass': password,
102 'pass': password,
102 'scheme': parsed_url.scheme,
103 'scheme': parsed_url.scheme,
103 'netloc': parsed_url.netloc,
104 'netloc': parsed_url.netloc,
104 'path': decoded_path
105 'path': urllib.quote(safe_str(decoded_path))
105 }
106 }
106
107
107 uri = uri_tmpl % uri_dict
108 uri = (uri_tmpl % uri_dict)
108 # generate another clone url by id
109 # generate another clone url by id
109 uri_dict.update(
110 uri_dict.update(
110 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
111 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
111 )
112 )
112 uri_id = uri_tmpl % uri_dict
113 uri_id = uri_tmpl % uri_dict
113
114
114 c.clone_repo_url = uri
115 c.clone_repo_url = uri
115 c.clone_repo_url_id = uri_id
116 c.clone_repo_url_id = uri_id
116 c.repo_tags = OrderedDict()
117 c.repo_tags = OrderedDict()
117 for name, hash_ in c.rhodecode_repo.tags.items()[:10]:
118 for name, hash_ in c.rhodecode_repo.tags.items()[:10]:
118 try:
119 try:
119 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
120 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
120 except ChangesetError:
121 except ChangesetError:
121 c.repo_tags[name] = EmptyChangeset(hash_)
122 c.repo_tags[name] = EmptyChangeset(hash_)
122
123
123 c.repo_branches = OrderedDict()
124 c.repo_branches = OrderedDict()
124 for name, hash_ in c.rhodecode_repo.branches.items()[:10]:
125 for name, hash_ in c.rhodecode_repo.branches.items()[:10]:
125 try:
126 try:
126 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
127 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
127 except ChangesetError:
128 except ChangesetError:
128 c.repo_branches[name] = EmptyChangeset(hash_)
129 c.repo_branches[name] = EmptyChangeset(hash_)
129
130
130 td = date.today() + timedelta(days=1)
131 td = date.today() + timedelta(days=1)
131 td_1m = td - timedelta(days=calendar.mdays[td.month])
132 td_1m = td - timedelta(days=calendar.mdays[td.month])
132 td_1y = td - timedelta(days=365)
133 td_1y = td - timedelta(days=365)
133
134
134 ts_min_m = mktime(td_1m.timetuple())
135 ts_min_m = mktime(td_1m.timetuple())
135 ts_min_y = mktime(td_1y.timetuple())
136 ts_min_y = mktime(td_1y.timetuple())
136 ts_max_y = mktime(td.timetuple())
137 ts_max_y = mktime(td.timetuple())
137
138
138 if dbrepo.enable_statistics:
139 if dbrepo.enable_statistics:
139 c.show_stats = True
140 c.show_stats = True
140 c.no_data_msg = _('No data loaded yet')
141 c.no_data_msg = _('No data loaded yet')
141 recurse_limit = 500 # don't recurse more than 500 times when parsing
142 recurse_limit = 500 # don't recurse more than 500 times when parsing
142 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y,
143 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y,
143 ts_max_y, recurse_limit)
144 ts_max_y, recurse_limit)
144 else:
145 else:
145 c.show_stats = False
146 c.show_stats = False
146 c.no_data_msg = _('Statistics are disabled for this repository')
147 c.no_data_msg = _('Statistics are disabled for this repository')
147 c.ts_min = ts_min_m
148 c.ts_min = ts_min_m
148 c.ts_max = ts_max_y
149 c.ts_max = ts_max_y
149
150
150 stats = self.sa.query(Statistics)\
151 stats = self.sa.query(Statistics)\
151 .filter(Statistics.repository == dbrepo)\
152 .filter(Statistics.repository == dbrepo)\
152 .scalar()
153 .scalar()
153
154
154 c.stats_percentage = 0
155 c.stats_percentage = 0
155
156
156 if stats and stats.languages:
157 if stats and stats.languages:
157 c.no_data = False is dbrepo.enable_statistics
158 c.no_data = False is dbrepo.enable_statistics
158 lang_stats_d = json.loads(stats.languages)
159 lang_stats_d = json.loads(stats.languages)
159 c.commit_data = stats.commit_activity
160 c.commit_data = stats.commit_activity
160 c.overview_data = stats.commit_activity_combined
161 c.overview_data = stats.commit_activity_combined
161
162
162 lang_stats = ((x, {"count": y,
163 lang_stats = ((x, {"count": y,
163 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
164 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
164 for x, y in lang_stats_d.items())
165 for x, y in lang_stats_d.items())
165
166
166 c.trending_languages = json.dumps(
167 c.trending_languages = json.dumps(
167 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
168 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
168 )
169 )
169 last_rev = stats.stat_on_revision + 1
170 last_rev = stats.stat_on_revision + 1
170 c.repo_last_rev = c.rhodecode_repo.count()\
171 c.repo_last_rev = c.rhodecode_repo.count()\
171 if c.rhodecode_repo.revisions else 0
172 if c.rhodecode_repo.revisions else 0
172 if last_rev == 0 or c.repo_last_rev == 0:
173 if last_rev == 0 or c.repo_last_rev == 0:
173 pass
174 pass
174 else:
175 else:
175 c.stats_percentage = '%.2f' % ((float((last_rev)) /
176 c.stats_percentage = '%.2f' % ((float((last_rev)) /
176 c.repo_last_rev) * 100)
177 c.repo_last_rev) * 100)
177 else:
178 else:
178 c.commit_data = json.dumps({})
179 c.commit_data = json.dumps({})
179 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
180 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
180 c.trending_languages = json.dumps({})
181 c.trending_languages = json.dumps({})
181 c.no_data = True
182 c.no_data = True
182
183
183 c.enable_downloads = dbrepo.enable_downloads
184 c.enable_downloads = dbrepo.enable_downloads
184 if c.enable_downloads:
185 if c.enable_downloads:
185 c.download_options = self._get_download_links(c.rhodecode_repo)
186 c.download_options = self._get_download_links(c.rhodecode_repo)
186
187
187 c.readme_data, c.readme_file = \
188 c.readme_data, c.readme_file = \
188 self.__get_readme_data(c.rhodecode_db_repo)
189 self.__get_readme_data(c.rhodecode_db_repo)
189 return render('summary/summary.html')
190 return render('summary/summary.html')
190
191
191 @NotAnonymous()
192 @NotAnonymous()
192 @jsonify
193 @jsonify
193 def repo_size(self, repo_name):
194 def repo_size(self, repo_name):
194 if request.is_xhr:
195 if request.is_xhr:
195 return c.rhodecode_db_repo._repo_size()
196 return c.rhodecode_db_repo._repo_size()
196 else:
197 else:
197 raise HTTPBadRequest()
198 raise HTTPBadRequest()
198
199
199 def __get_readme_data(self, db_repo):
200 def __get_readme_data(self, db_repo):
200 repo_name = db_repo.repo_name
201 repo_name = db_repo.repo_name
201
202
202 @cache_region('long_term')
203 @cache_region('long_term')
203 def _get_readme_from_cache(key):
204 def _get_readme_from_cache(key):
204 readme_data = None
205 readme_data = None
205 readme_file = None
206 readme_file = None
206 log.debug('Looking for README file')
207 log.debug('Looking for README file')
207 try:
208 try:
208 # get's the landing revision! or tip if fails
209 # get's the landing revision! or tip if fails
209 cs = db_repo.get_landing_changeset()
210 cs = db_repo.get_landing_changeset()
210 if isinstance(cs, EmptyChangeset):
211 if isinstance(cs, EmptyChangeset):
211 raise EmptyRepositoryError()
212 raise EmptyRepositoryError()
212 renderer = MarkupRenderer()
213 renderer = MarkupRenderer()
213 for f in README_FILES:
214 for f in README_FILES:
214 try:
215 try:
215 readme = cs.get_node(f)
216 readme = cs.get_node(f)
216 if not isinstance(readme, FileNode):
217 if not isinstance(readme, FileNode):
217 continue
218 continue
218 readme_file = f
219 readme_file = f
219 log.debug('Found README file `%s` rendering...' %
220 log.debug('Found README file `%s` rendering...' %
220 readme_file)
221 readme_file)
221 readme_data = renderer.render(readme.content, f)
222 readme_data = renderer.render(readme.content, f)
222 break
223 break
223 except NodeDoesNotExistError:
224 except NodeDoesNotExistError:
224 continue
225 continue
225 except ChangesetError:
226 except ChangesetError:
226 log.error(traceback.format_exc())
227 log.error(traceback.format_exc())
227 pass
228 pass
228 except EmptyRepositoryError:
229 except EmptyRepositoryError:
229 pass
230 pass
230 except Exception:
231 except Exception:
231 log.error(traceback.format_exc())
232 log.error(traceback.format_exc())
232
233
233 return readme_data, readme_file
234 return readme_data, readme_file
234
235
235 key = repo_name + '_README'
236 key = repo_name + '_README'
236 inv = CacheInvalidation.invalidate(key)
237 inv = CacheInvalidation.invalidate(key)
237 if inv is not None:
238 if inv is not None:
238 region_invalidate(_get_readme_from_cache, None, key)
239 region_invalidate(_get_readme_from_cache, None, key)
239 CacheInvalidation.set_valid(inv.cache_key)
240 CacheInvalidation.set_valid(inv.cache_key)
240 return _get_readme_from_cache(key)
241 return _get_readme_from_cache(key)
241
242
242 def _get_download_links(self, repo):
243 def _get_download_links(self, repo):
243
244
244 download_l = []
245 download_l = []
245
246
246 branches_group = ([], _("Branches"))
247 branches_group = ([], _("Branches"))
247 tags_group = ([], _("Tags"))
248 tags_group = ([], _("Tags"))
248
249
249 for name, chs in c.rhodecode_repo.branches.items():
250 for name, chs in c.rhodecode_repo.branches.items():
250 #chs = chs.split(':')[-1]
251 #chs = chs.split(':')[-1]
251 branches_group[0].append((chs, name),)
252 branches_group[0].append((chs, name),)
252 download_l.append(branches_group)
253 download_l.append(branches_group)
253
254
254 for name, chs in c.rhodecode_repo.tags.items():
255 for name, chs in c.rhodecode_repo.tags.items():
255 #chs = chs.split(':')[-1]
256 #chs = chs.split(':')[-1]
256 tags_group[0].append((chs, name),)
257 tags_group[0].append((chs, name),)
257 download_l.append(tags_group)
258 download_l.append(tags_group)
258
259
259 return download_l
260 return download_l
@@ -1,735 +1,735 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('%s Summary') % c.repo_name} &middot; ${c.rhodecode_name}
4 ${_('%s Summary') % c.repo_name} &middot; ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${_('Summary')}
8 ${_('Summary')}
9 </%def>
9 </%def>
10
10
11 <%def name="page_nav()">
11 <%def name="page_nav()">
12 ${self.menu('repositories')}
12 ${self.menu('repositories')}
13 </%def>
13 </%def>
14
14
15 <%def name="head_extra()">
15 <%def name="head_extra()">
16 <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
16 <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
17 <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
17 <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 ${self.context_bar('summary')}
21 ${self.context_bar('summary')}
22 <%
22 <%
23 summary = lambda n:{False:'summary-short'}.get(n)
23 summary = lambda n:{False:'summary-short'}.get(n)
24 %>
24 %>
25 %if c.show_stats:
25 %if c.show_stats:
26 <div class="box box-left">
26 <div class="box box-left">
27 %else:
27 %else:
28 <div class="box">
28 <div class="box">
29 %endif
29 %endif
30 <!-- box / title -->
30 <!-- box / title -->
31 <div class="title">
31 <div class="title">
32 ${self.breadcrumbs()}
32 ${self.breadcrumbs()}
33 </div>
33 </div>
34 <!-- end box / title -->
34 <!-- end box / title -->
35 <div class="form">
35 <div class="form">
36 <div id="summary" class="fields">
36 <div id="summary" class="fields">
37
37
38 <div class="field">
38 <div class="field">
39 <div class="label-summary">
39 <div class="label-summary">
40 <label>${_('Name')}:</label>
40 <label>${_('Name')}:</label>
41 </div>
41 </div>
42 <div class="input ${summary(c.show_stats)}">
42 <div class="input ${summary(c.show_stats)}">
43
43
44 ## locking icon
44 ## locking icon
45 %if c.rhodecode_db_repo.enable_locking:
45 %if c.rhodecode_db_repo.enable_locking:
46 %if c.rhodecode_db_repo.locked[0]:
46 %if c.rhodecode_db_repo.locked[0]:
47 <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span>
47 <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span>
48 %else:
48 %else:
49 <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span>
49 <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span>
50 %endif
50 %endif
51 %endif
51 %endif
52 ##REPO TYPE
52 ##REPO TYPE
53 %if h.is_hg(c.dbrepo):
53 %if h.is_hg(c.dbrepo):
54 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
54 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
55 %endif
55 %endif
56 %if h.is_git(c.dbrepo):
56 %if h.is_git(c.dbrepo):
57 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
57 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
58 %endif
58 %endif
59
59
60 ##PUBLIC/PRIVATE
60 ##PUBLIC/PRIVATE
61 %if c.dbrepo.private:
61 %if c.dbrepo.private:
62 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
62 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
63 %else:
63 %else:
64 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
64 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
65 %endif
65 %endif
66
66
67 ##REPO NAME
67 ##REPO NAME
68 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
68 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
69
69
70 ##FORK
70 ##FORK
71 %if c.dbrepo.fork:
71 %if c.dbrepo.fork:
72 <div style="margin-top:5px;clear:both">
72 <div style="margin-top:5px;clear:both">
73 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
73 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
74 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
74 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
75 </a>
75 </a>
76 </div>
76 </div>
77 %endif
77 %endif
78 ##REMOTE
78 ##REMOTE
79 %if c.dbrepo.clone_uri:
79 %if c.dbrepo.clone_uri:
80 <div style="margin-top:5px;clear:both">
80 <div style="margin-top:5px;clear:both">
81 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
81 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
82 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
82 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
83 </a>
83 </a>
84 </div>
84 </div>
85 %endif
85 %endif
86 </div>
86 </div>
87 </div>
87 </div>
88
88
89 <div class="field">
89 <div class="field">
90 <div class="label-summary">
90 <div class="label-summary">
91 <label>${_('Description')}:</label>
91 <label>${_('Description')}:</label>
92 </div>
92 </div>
93 %if c.visual.stylify_metatags:
93 %if c.visual.stylify_metatags:
94 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
94 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
95 %else:
95 %else:
96 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
96 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
97 %endif
97 %endif
98 </div>
98 </div>
99
99
100 <div class="field">
100 <div class="field">
101 <div class="label-summary">
101 <div class="label-summary">
102 <label>${_('Contact')}:</label>
102 <label>${_('Contact')}:</label>
103 </div>
103 </div>
104 <div class="input ${summary(c.show_stats)}">
104 <div class="input ${summary(c.show_stats)}">
105 <div class="gravatar">
105 <div class="gravatar">
106 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
106 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
107 </div>
107 </div>
108 ${_('Username')}: ${c.dbrepo.user.username}<br/>
108 ${_('Username')}: ${c.dbrepo.user.username}<br/>
109 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
109 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
110 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
110 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
111 </div>
111 </div>
112 </div>
112 </div>
113
113
114 <div class="field">
114 <div class="field">
115 <div class="label-summary">
115 <div class="label-summary">
116 <label>${_('Clone url')}:</label>
116 <label>${_('Clone url')}:</label>
117 </div>
117 </div>
118 <div class="input ${summary(c.show_stats)}">
118 <div class="input ${summary(c.show_stats)}">
119 <input style="width:80%" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
119 <input style="width:${'75%' if c.show_stats else '80%'}" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
120 <input style="display:none;width:80%" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
120 <input style="display:none;width:${'75%' if c.show_stats else '80%'}" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
121 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
121 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
122 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
122 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
123 </div>
123 </div>
124 </div>
124 </div>
125
125
126 <div class="field">
126 <div class="field">
127 <div class="label-summary">
127 <div class="label-summary">
128 <label>${_('Trending files')}:</label>
128 <label>${_('Trending files')}:</label>
129 </div>
129 </div>
130 <div class="input ${summary(c.show_stats)}">
130 <div class="input ${summary(c.show_stats)}">
131 %if c.show_stats:
131 %if c.show_stats:
132 <div id="lang_stats"></div>
132 <div id="lang_stats"></div>
133 %else:
133 %else:
134 ${_('Statistics are disabled for this repository')}
134 ${_('Statistics are disabled for this repository')}
135 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
135 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
136 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
136 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
137 %endif
137 %endif
138 %endif
138 %endif
139 </div>
139 </div>
140 </div>
140 </div>
141
141
142 <div class="field">
142 <div class="field">
143 <div class="label-summary">
143 <div class="label-summary">
144 <label>${_('Download')}:</label>
144 <label>${_('Download')}:</label>
145 </div>
145 </div>
146 <div class="input ${summary(c.show_stats)}">
146 <div class="input ${summary(c.show_stats)}">
147 %if len(c.rhodecode_repo.revisions) == 0:
147 %if len(c.rhodecode_repo.revisions) == 0:
148 ${_('There are no downloads yet')}
148 ${_('There are no downloads yet')}
149 %elif not c.enable_downloads:
149 %elif not c.enable_downloads:
150 ${_('Downloads are disabled for this repository')}
150 ${_('Downloads are disabled for this repository')}
151 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
151 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
152 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
152 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
153 %endif
153 %endif
154 %else:
154 %else:
155 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
155 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
156 <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
156 <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
157 <span style="vertical-align: bottom">
157 <span style="vertical-align: bottom">
158 <input id="archive_subrepos" type="checkbox" name="subrepos" />
158 <input id="archive_subrepos" type="checkbox" name="subrepos" />
159 <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
159 <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
160 </span>
160 </span>
161 %endif
161 %endif
162 </div>
162 </div>
163 </div>
163 </div>
164 </div>
164 </div>
165 <div id="summary-menu-stats">
165 <div id="summary-menu-stats">
166 <ul>
166 <ul>
167 <li>
167 <li>
168 <a class="followers" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
168 <a class="followers" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
169 ${_('Followers')}
169 ${_('Followers')}
170 <span style="float:right" id="current_followers_count">${c.repository_followers}</span>
170 <span style="float:right" id="current_followers_count">${c.repository_followers}</span>
171 </a>
171 </a>
172 </li>
172 </li>
173 <li>
173 <li>
174 <a class="forks" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
174 <a class="forks" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
175 ${_('Forks')}
175 ${_('Forks')}
176 <span style="float:right">${c.repository_forks}</span>
176 <span style="float:right">${c.repository_forks}</span>
177 </a>
177 </a>
178 </li>
178 </li>
179
179
180 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
180 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
181 <li>
181 <li>
182 ${h.link_to(_('Settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}
182 ${h.link_to(_('Settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}
183 </li>
183 </li>
184 %endif
184 %endif
185
185
186 <li>
186 <li>
187 %if c.rhodecode_user.username != 'default':
187 %if c.rhodecode_user.username != 'default':
188 ${h.link_to(_('Feed'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='feed')}
188 ${h.link_to(_('Feed'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='feed')}
189 %else:
189 %else:
190 ${h.link_to(_('Feed'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='feed')}
190 ${h.link_to(_('Feed'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='feed')}
191 %endif
191 %endif
192 </li>
192 </li>
193
193
194 %if c.rhodecode_user.username != 'default':
194 %if c.rhodecode_user.username != 'default':
195 <li class="repo_size">
195 <li class="repo_size">
196 <a href="#" class="repo-size" onclick="javascript:showRepoSize('repo_size_2','${c.dbrepo.repo_name}','${str(h.get_token())}')">${_('Repository Size')}</a>
196 <a href="#" class="repo-size" onclick="javascript:showRepoSize('repo_size_2','${c.dbrepo.repo_name}','${str(h.get_token())}')">${_('Repository Size')}</a>
197 <span id="repo_size_2"></span>
197 <span id="repo_size_2"></span>
198 </li>
198 </li>
199 %endif
199 %endif
200 </ul>
200 </ul>
201 </div>
201 </div>
202 </div>
202 </div>
203 </div>
203 </div>
204
204
205 %if c.show_stats:
205 %if c.show_stats:
206 <div class="box box-right" style="min-height:455px">
206 <div class="box box-right" style="min-height:455px">
207 <!-- box / title -->
207 <!-- box / title -->
208 <div class="title">
208 <div class="title">
209 <h5>${_('Commit activity by day / author')}</h5>
209 <h5>${_('Commit activity by day / author')}</h5>
210 </div>
210 </div>
211
211
212 <div class="graph">
212 <div class="graph">
213 <div style="padding:0 10px 10px 17px;">
213 <div style="padding:0 10px 10px 17px;">
214 %if c.no_data:
214 %if c.no_data:
215 ${c.no_data_msg}
215 ${c.no_data_msg}
216 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
216 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
217 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
217 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
218 %endif
218 %endif
219 %else:
219 %else:
220 ${_('Stats gathered: ')} ${c.stats_percentage}%
220 ${_('Stats gathered: ')} ${c.stats_percentage}%
221 %endif
221 %endif
222 </div>
222 </div>
223 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
223 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
224 <div style="clear: both;height: 10px"></div>
224 <div style="clear: both;height: 10px"></div>
225 <div id="overview" style="width:450px;height:100px;float:left"></div>
225 <div id="overview" style="width:450px;height:100px;float:left"></div>
226
226
227 <div id="legend_data" style="clear:both;margin-top:10px;">
227 <div id="legend_data" style="clear:both;margin-top:10px;">
228 <div id="legend_container"></div>
228 <div id="legend_container"></div>
229 <div id="legend_choices">
229 <div id="legend_choices">
230 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
230 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
231 </div>
231 </div>
232 </div>
232 </div>
233 </div>
233 </div>
234 </div>
234 </div>
235 %endif
235 %endif
236
236
237 <div class="box">
237 <div class="box">
238 <div class="title">
238 <div class="title">
239 <div class="breadcrumbs">
239 <div class="breadcrumbs">
240 %if c.repo_changesets:
240 %if c.repo_changesets:
241 ${h.link_to(_('Latest changes'),h.url('changelog_home',repo_name=c.repo_name))}
241 ${h.link_to(_('Latest changes'),h.url('changelog_home',repo_name=c.repo_name))}
242 %else:
242 %else:
243 ${_('Quick start')}
243 ${_('Quick start')}
244 %endif
244 %endif
245 </div>
245 </div>
246 </div>
246 </div>
247 <div class="table">
247 <div class="table">
248 <div id="shortlog_data">
248 <div id="shortlog_data">
249 <%include file='../shortlog/shortlog_data.html'/>
249 <%include file='../shortlog/shortlog_data.html'/>
250 </div>
250 </div>
251 </div>
251 </div>
252 </div>
252 </div>
253
253
254 %if c.readme_data:
254 %if c.readme_data:
255 <div id="readme" class="anchor">
255 <div id="readme" class="anchor">
256 <div class="box" style="background-color: #FAFAFA">
256 <div class="box" style="background-color: #FAFAFA">
257 <div class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
257 <div class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
258 <div class="breadcrumbs">
258 <div class="breadcrumbs">
259 <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
259 <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
260 <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
260 <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
261 </div>
261 </div>
262 </div>
262 </div>
263 <div class="readme">
263 <div class="readme">
264 <div class="readme_box">
264 <div class="readme_box">
265 ${c.readme_data|n}
265 ${c.readme_data|n}
266 </div>
266 </div>
267 </div>
267 </div>
268 </div>
268 </div>
269 </div>
269 </div>
270 %endif
270 %endif
271
271
272 <script type="text/javascript">
272 <script type="text/javascript">
273 var clone_url = 'clone_url';
273 var clone_url = 'clone_url';
274 YUE.on(clone_url,'click',function(e){
274 YUE.on(clone_url,'click',function(e){
275 if(YUD.hasClass(clone_url,'selected')){
275 if(YUD.hasClass(clone_url,'selected')){
276 return
276 return
277 }
277 }
278 else{
278 else{
279 YUD.addClass(clone_url,'selected');
279 YUD.addClass(clone_url,'selected');
280 YUD.get(clone_url).select();
280 YUD.get(clone_url).select();
281 }
281 }
282 })
282 })
283
283
284 YUE.on('clone_by_name','click',function(e){
284 YUE.on('clone_by_name','click',function(e){
285 // show url by name and hide name button
285 // show url by name and hide name button
286 YUD.setStyle('clone_url','display','');
286 YUD.setStyle('clone_url','display','');
287 YUD.setStyle('clone_by_name','display','none');
287 YUD.setStyle('clone_by_name','display','none');
288
288
289 // hide url by id and show name button
289 // hide url by id and show name button
290 YUD.setStyle('clone_by_id','display','');
290 YUD.setStyle('clone_by_id','display','');
291 YUD.setStyle('clone_url_id','display','none');
291 YUD.setStyle('clone_url_id','display','none');
292
292
293 })
293 })
294 YUE.on('clone_by_id','click',function(e){
294 YUE.on('clone_by_id','click',function(e){
295
295
296 // show url by id and hide id button
296 // show url by id and hide id button
297 YUD.setStyle('clone_by_id','display','none');
297 YUD.setStyle('clone_by_id','display','none');
298 YUD.setStyle('clone_url_id','display','');
298 YUD.setStyle('clone_url_id','display','');
299
299
300 // hide url by name and show id button
300 // hide url by name and show id button
301 YUD.setStyle('clone_by_name','display','');
301 YUD.setStyle('clone_by_name','display','');
302 YUD.setStyle('clone_url','display','none');
302 YUD.setStyle('clone_url','display','none');
303 })
303 })
304
304
305
305
306 var tmpl_links = {};
306 var tmpl_links = {};
307 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
307 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
308 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
308 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
309 %endfor
309 %endfor
310
310
311 YUE.on(['download_options','archive_subrepos'],'change',function(e){
311 YUE.on(['download_options','archive_subrepos'],'change',function(e){
312 var sm = YUD.get('download_options');
312 var sm = YUD.get('download_options');
313 var new_cs = sm.options[sm.selectedIndex];
313 var new_cs = sm.options[sm.selectedIndex];
314
314
315 for(k in tmpl_links){
315 for(k in tmpl_links){
316 var s = YUD.get(k+'_link');
316 var s = YUD.get(k+'_link');
317 if(s){
317 if(s){
318 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
318 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
319 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
319 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
320 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
320 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
321
321
322 var url = tmpl_links[k].replace('__CS__',new_cs.value);
322 var url = tmpl_links[k].replace('__CS__',new_cs.value);
323 var subrepos = YUD.get('archive_subrepos').checked;
323 var subrepos = YUD.get('archive_subrepos').checked;
324 url = url.replace('__SUB__',subrepos);
324 url = url.replace('__SUB__',subrepos);
325 url = url.replace('__NAME__',title_tmpl);
325 url = url.replace('__NAME__',title_tmpl);
326 s.innerHTML = url
326 s.innerHTML = url
327 }
327 }
328 }
328 }
329 });
329 });
330 </script>
330 </script>
331 %if c.show_stats:
331 %if c.show_stats:
332 <script type="text/javascript">
332 <script type="text/javascript">
333 var data = ${c.trending_languages|n};
333 var data = ${c.trending_languages|n};
334 var total = 0;
334 var total = 0;
335 var no_data = true;
335 var no_data = true;
336 var tbl = document.createElement('table');
336 var tbl = document.createElement('table');
337 tbl.setAttribute('class','trending_language_tbl');
337 tbl.setAttribute('class','trending_language_tbl');
338 var cnt = 0;
338 var cnt = 0;
339 for (var i=0;i<data.length;i++){
339 for (var i=0;i<data.length;i++){
340 total+= data[i][1].count;
340 total+= data[i][1].count;
341 }
341 }
342 for (var i=0;i<data.length;i++){
342 for (var i=0;i<data.length;i++){
343 cnt += 1;
343 cnt += 1;
344 no_data = false;
344 no_data = false;
345
345
346 var hide = cnt>2;
346 var hide = cnt>2;
347 var tr = document.createElement('tr');
347 var tr = document.createElement('tr');
348 if (hide){
348 if (hide){
349 tr.setAttribute('style','display:none');
349 tr.setAttribute('style','display:none');
350 tr.setAttribute('class','stats_hidden');
350 tr.setAttribute('class','stats_hidden');
351 }
351 }
352 var k = data[i][0];
352 var k = data[i][0];
353 var obj = data[i][1];
353 var obj = data[i][1];
354 var percentage = Math.round((obj.count/total*100),2);
354 var percentage = Math.round((obj.count/total*100),2);
355
355
356 var td1 = document.createElement('td');
356 var td1 = document.createElement('td');
357 td1.width = 150;
357 td1.width = 150;
358 var trending_language_label = document.createElement('div');
358 var trending_language_label = document.createElement('div');
359 trending_language_label.innerHTML = obj.desc+" ("+k+")";
359 trending_language_label.innerHTML = obj.desc+" ("+k+")";
360 td1.appendChild(trending_language_label);
360 td1.appendChild(trending_language_label);
361
361
362 var td2 = document.createElement('td');
362 var td2 = document.createElement('td');
363 td2.setAttribute('style','padding-right:14px !important');
363 td2.setAttribute('style','padding-right:14px !important');
364 var trending_language = document.createElement('div');
364 var trending_language = document.createElement('div');
365 var nr_files = obj.count+" ${_('files')}";
365 var nr_files = obj.count+" ${_('files')}";
366
366
367 trending_language.title = k+" "+nr_files;
367 trending_language.title = k+" "+nr_files;
368
368
369 if (percentage>22){
369 if (percentage>22){
370 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
370 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
371 }
371 }
372 else{
372 else{
373 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
373 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
374 }
374 }
375
375
376 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
376 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
377 trending_language.style.width=percentage+"%";
377 trending_language.style.width=percentage+"%";
378 td2.appendChild(trending_language);
378 td2.appendChild(trending_language);
379
379
380 tr.appendChild(td1);
380 tr.appendChild(td1);
381 tr.appendChild(td2);
381 tr.appendChild(td2);
382 tbl.appendChild(tr);
382 tbl.appendChild(tr);
383 if(cnt == 3){
383 if(cnt == 3){
384 var show_more = document.createElement('tr');
384 var show_more = document.createElement('tr');
385 var td = document.createElement('td');
385 var td = document.createElement('td');
386 lnk = document.createElement('a');
386 lnk = document.createElement('a');
387
387
388 lnk.href='#';
388 lnk.href='#';
389 lnk.innerHTML = "${_('show more')}";
389 lnk.innerHTML = "${_('show more')}";
390 lnk.id='code_stats_show_more';
390 lnk.id='code_stats_show_more';
391 td.appendChild(lnk);
391 td.appendChild(lnk);
392
392
393 show_more.appendChild(td);
393 show_more.appendChild(td);
394 show_more.appendChild(document.createElement('td'));
394 show_more.appendChild(document.createElement('td'));
395 tbl.appendChild(show_more);
395 tbl.appendChild(show_more);
396 }
396 }
397
397
398 }
398 }
399
399
400 YUD.get('lang_stats').appendChild(tbl);
400 YUD.get('lang_stats').appendChild(tbl);
401 YUE.on('code_stats_show_more','click',function(){
401 YUE.on('code_stats_show_more','click',function(){
402 l = YUD.getElementsByClassName('stats_hidden')
402 l = YUD.getElementsByClassName('stats_hidden')
403 for (e in l){
403 for (e in l){
404 YUD.setStyle(l[e],'display','');
404 YUD.setStyle(l[e],'display','');
405 };
405 };
406 YUD.setStyle(YUD.get('code_stats_show_more'),
406 YUD.setStyle(YUD.get('code_stats_show_more'),
407 'display','none');
407 'display','none');
408 });
408 });
409 </script>
409 </script>
410 <script type="text/javascript">
410 <script type="text/javascript">
411 /**
411 /**
412 * Plots summary graph
412 * Plots summary graph
413 *
413 *
414 * @class SummaryPlot
414 * @class SummaryPlot
415 * @param {from} initial from for detailed graph
415 * @param {from} initial from for detailed graph
416 * @param {to} initial to for detailed graph
416 * @param {to} initial to for detailed graph
417 * @param {dataset}
417 * @param {dataset}
418 * @param {overview_dataset}
418 * @param {overview_dataset}
419 */
419 */
420 function SummaryPlot(from,to,dataset,overview_dataset) {
420 function SummaryPlot(from,to,dataset,overview_dataset) {
421 var initial_ranges = {
421 var initial_ranges = {
422 "xaxis":{
422 "xaxis":{
423 "from":from,
423 "from":from,
424 "to":to,
424 "to":to,
425 },
425 },
426 };
426 };
427 var dataset = dataset;
427 var dataset = dataset;
428 var overview_dataset = [overview_dataset];
428 var overview_dataset = [overview_dataset];
429 var choiceContainer = YUD.get("legend_choices");
429 var choiceContainer = YUD.get("legend_choices");
430 var choiceContainerTable = YUD.get("legend_choices_tables");
430 var choiceContainerTable = YUD.get("legend_choices_tables");
431 var plotContainer = YUD.get('commit_history');
431 var plotContainer = YUD.get('commit_history');
432 var overviewContainer = YUD.get('overview');
432 var overviewContainer = YUD.get('overview');
433
433
434 var plot_options = {
434 var plot_options = {
435 bars: {show:true,align:'center',lineWidth:4},
435 bars: {show:true,align:'center',lineWidth:4},
436 legend: {show:true, container:"legend_container"},
436 legend: {show:true, container:"legend_container"},
437 points: {show:true,radius:0,fill:false},
437 points: {show:true,radius:0,fill:false},
438 yaxis: {tickDecimals:0,},
438 yaxis: {tickDecimals:0,},
439 xaxis: {
439 xaxis: {
440 mode: "time",
440 mode: "time",
441 timeformat: "%d/%m",
441 timeformat: "%d/%m",
442 min:from,
442 min:from,
443 max:to,
443 max:to,
444 },
444 },
445 grid: {
445 grid: {
446 hoverable: true,
446 hoverable: true,
447 clickable: true,
447 clickable: true,
448 autoHighlight:true,
448 autoHighlight:true,
449 color: "#999"
449 color: "#999"
450 },
450 },
451 //selection: {mode: "x"}
451 //selection: {mode: "x"}
452 };
452 };
453 var overview_options = {
453 var overview_options = {
454 legend:{show:false},
454 legend:{show:false},
455 bars: {show:true,barWidth: 2,},
455 bars: {show:true,barWidth: 2,},
456 shadowSize: 0,
456 shadowSize: 0,
457 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
457 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
458 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
458 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
459 grid: {color: "#999",},
459 grid: {color: "#999",},
460 selection: {mode: "x"}
460 selection: {mode: "x"}
461 };
461 };
462
462
463 /**
463 /**
464 *get dummy data needed in few places
464 *get dummy data needed in few places
465 */
465 */
466 function getDummyData(label){
466 function getDummyData(label){
467 return {"label":label,
467 return {"label":label,
468 "data":[{"time":0,
468 "data":[{"time":0,
469 "commits":0,
469 "commits":0,
470 "added":0,
470 "added":0,
471 "changed":0,
471 "changed":0,
472 "removed":0,
472 "removed":0,
473 }],
473 }],
474 "schema":["commits"],
474 "schema":["commits"],
475 "color":'#ffffff',
475 "color":'#ffffff',
476 }
476 }
477 }
477 }
478
478
479 /**
479 /**
480 * generate checkboxes accordindly to data
480 * generate checkboxes accordindly to data
481 * @param keys
481 * @param keys
482 * @returns
482 * @returns
483 */
483 */
484 function generateCheckboxes(data) {
484 function generateCheckboxes(data) {
485 //append checkboxes
485 //append checkboxes
486 var i = 0;
486 var i = 0;
487 choiceContainerTable.innerHTML = '';
487 choiceContainerTable.innerHTML = '';
488 for(var pos in data) {
488 for(var pos in data) {
489
489
490 data[pos].color = i;
490 data[pos].color = i;
491 i++;
491 i++;
492 if(data[pos].label != ''){
492 if(data[pos].label != ''){
493 choiceContainerTable.innerHTML +=
493 choiceContainerTable.innerHTML +=
494 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
494 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
495 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
495 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
496 }
496 }
497 }
497 }
498 }
498 }
499
499
500 /**
500 /**
501 * ToolTip show
501 * ToolTip show
502 */
502 */
503 function showTooltip(x, y, contents) {
503 function showTooltip(x, y, contents) {
504 var div=document.getElementById('tooltip');
504 var div=document.getElementById('tooltip');
505 if(!div) {
505 if(!div) {
506 div = document.createElement('div');
506 div = document.createElement('div');
507 div.id="tooltip";
507 div.id="tooltip";
508 div.style.position="absolute";
508 div.style.position="absolute";
509 div.style.border='1px solid #fdd';
509 div.style.border='1px solid #fdd';
510 div.style.padding='2px';
510 div.style.padding='2px';
511 div.style.backgroundColor='#fee';
511 div.style.backgroundColor='#fee';
512 document.body.appendChild(div);
512 document.body.appendChild(div);
513 }
513 }
514 YUD.setStyle(div, 'opacity', 0);
514 YUD.setStyle(div, 'opacity', 0);
515 div.innerHTML = contents;
515 div.innerHTML = contents;
516 div.style.top=(y + 5) + "px";
516 div.style.top=(y + 5) + "px";
517 div.style.left=(x + 5) + "px";
517 div.style.left=(x + 5) + "px";
518
518
519 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
519 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
520 anim.animate();
520 anim.animate();
521 }
521 }
522
522
523 /**
523 /**
524 * This function will detect if selected period has some changesets
524 * This function will detect if selected period has some changesets
525 for this user if it does this data is then pushed for displaying
525 for this user if it does this data is then pushed for displaying
526 Additionally it will only display users that are selected by the checkbox
526 Additionally it will only display users that are selected by the checkbox
527 */
527 */
528 function getDataAccordingToRanges(ranges) {
528 function getDataAccordingToRanges(ranges) {
529
529
530 var data = [];
530 var data = [];
531 var new_dataset = {};
531 var new_dataset = {};
532 var keys = [];
532 var keys = [];
533 var max_commits = 0;
533 var max_commits = 0;
534 for(var key in dataset){
534 for(var key in dataset){
535
535
536 for(var ds in dataset[key].data){
536 for(var ds in dataset[key].data){
537 commit_data = dataset[key].data[ds];
537 commit_data = dataset[key].data[ds];
538 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
538 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
539
539
540 if(new_dataset[key] === undefined){
540 if(new_dataset[key] === undefined){
541 new_dataset[key] = {data:[],schema:["commits"],label:key};
541 new_dataset[key] = {data:[],schema:["commits"],label:key};
542 }
542 }
543 new_dataset[key].data.push(commit_data);
543 new_dataset[key].data.push(commit_data);
544 }
544 }
545 }
545 }
546 if (new_dataset[key] !== undefined){
546 if (new_dataset[key] !== undefined){
547 data.push(new_dataset[key]);
547 data.push(new_dataset[key]);
548 }
548 }
549 }
549 }
550
550
551 if (data.length > 0){
551 if (data.length > 0){
552 return data;
552 return data;
553 }
553 }
554 else{
554 else{
555 //just return dummy data for graph to plot itself
555 //just return dummy data for graph to plot itself
556 return [getDummyData('')];
556 return [getDummyData('')];
557 }
557 }
558 }
558 }
559
559
560 /**
560 /**
561 * redraw using new checkbox data
561 * redraw using new checkbox data
562 */
562 */
563 function plotchoiced(e,args){
563 function plotchoiced(e,args){
564 var cur_data = args[0];
564 var cur_data = args[0];
565 var cur_ranges = args[1];
565 var cur_ranges = args[1];
566
566
567 var new_data = [];
567 var new_data = [];
568 var inputs = choiceContainer.getElementsByTagName("input");
568 var inputs = choiceContainer.getElementsByTagName("input");
569
569
570 //show only checked labels
570 //show only checked labels
571 for(var i=0; i<inputs.length; i++) {
571 for(var i=0; i<inputs.length; i++) {
572 var checkbox_key = inputs[i].name;
572 var checkbox_key = inputs[i].name;
573
573
574 if(inputs[i].checked){
574 if(inputs[i].checked){
575 for(var d in cur_data){
575 for(var d in cur_data){
576 if(cur_data[d].label == checkbox_key){
576 if(cur_data[d].label == checkbox_key){
577 new_data.push(cur_data[d]);
577 new_data.push(cur_data[d]);
578 }
578 }
579 }
579 }
580 }
580 }
581 else{
581 else{
582 //push dummy data to not hide the label
582 //push dummy data to not hide the label
583 new_data.push(getDummyData(checkbox_key));
583 new_data.push(getDummyData(checkbox_key));
584 }
584 }
585 }
585 }
586
586
587 var new_options = YAHOO.lang.merge(plot_options, {
587 var new_options = YAHOO.lang.merge(plot_options, {
588 xaxis: {
588 xaxis: {
589 min: cur_ranges.xaxis.from,
589 min: cur_ranges.xaxis.from,
590 max: cur_ranges.xaxis.to,
590 max: cur_ranges.xaxis.to,
591 mode:"time",
591 mode:"time",
592 timeformat: "%d/%m",
592 timeformat: "%d/%m",
593 },
593 },
594 });
594 });
595 if (!new_data){
595 if (!new_data){
596 new_data = [[0,1]];
596 new_data = [[0,1]];
597 }
597 }
598 // do the zooming
598 // do the zooming
599 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
599 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
600
600
601 plot.subscribe("plotselected", plotselected);
601 plot.subscribe("plotselected", plotselected);
602
602
603 //resubscribe plothover
603 //resubscribe plothover
604 plot.subscribe("plothover", plothover);
604 plot.subscribe("plothover", plothover);
605
605
606 // don't fire event on the overview to prevent eternal loop
606 // don't fire event on the overview to prevent eternal loop
607 overview.setSelection(cur_ranges, true);
607 overview.setSelection(cur_ranges, true);
608
608
609 }
609 }
610
610
611 /**
611 /**
612 * plot only selected items from overview
612 * plot only selected items from overview
613 * @param ranges
613 * @param ranges
614 * @returns
614 * @returns
615 */
615 */
616 function plotselected(ranges,cur_data) {
616 function plotselected(ranges,cur_data) {
617 //updates the data for new plot
617 //updates the data for new plot
618 var data = getDataAccordingToRanges(ranges);
618 var data = getDataAccordingToRanges(ranges);
619 generateCheckboxes(data);
619 generateCheckboxes(data);
620
620
621 var new_options = YAHOO.lang.merge(plot_options, {
621 var new_options = YAHOO.lang.merge(plot_options, {
622 xaxis: {
622 xaxis: {
623 min: ranges.xaxis.from,
623 min: ranges.xaxis.from,
624 max: ranges.xaxis.to,
624 max: ranges.xaxis.to,
625 mode:"time",
625 mode:"time",
626 timeformat: "%d/%m",
626 timeformat: "%d/%m",
627 },
627 },
628 });
628 });
629 // do the zooming
629 // do the zooming
630 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
630 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
631
631
632 plot.subscribe("plotselected", plotselected);
632 plot.subscribe("plotselected", plotselected);
633
633
634 //resubscribe plothover
634 //resubscribe plothover
635 plot.subscribe("plothover", plothover);
635 plot.subscribe("plothover", plothover);
636
636
637 // don't fire event on the overview to prevent eternal loop
637 // don't fire event on the overview to prevent eternal loop
638 overview.setSelection(ranges, true);
638 overview.setSelection(ranges, true);
639
639
640 //resubscribe choiced
640 //resubscribe choiced
641 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
641 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
642 }
642 }
643
643
644 var previousPoint = null;
644 var previousPoint = null;
645
645
646 function plothover(o) {
646 function plothover(o) {
647 var pos = o.pos;
647 var pos = o.pos;
648 var item = o.item;
648 var item = o.item;
649
649
650 //YUD.get("x").innerHTML = pos.x.toFixed(2);
650 //YUD.get("x").innerHTML = pos.x.toFixed(2);
651 //YUD.get("y").innerHTML = pos.y.toFixed(2);
651 //YUD.get("y").innerHTML = pos.y.toFixed(2);
652 if (item) {
652 if (item) {
653 if (previousPoint != item.datapoint) {
653 if (previousPoint != item.datapoint) {
654 previousPoint = item.datapoint;
654 previousPoint = item.datapoint;
655
655
656 var tooltip = YUD.get("tooltip");
656 var tooltip = YUD.get("tooltip");
657 if(tooltip) {
657 if(tooltip) {
658 tooltip.parentNode.removeChild(tooltip);
658 tooltip.parentNode.removeChild(tooltip);
659 }
659 }
660 var x = item.datapoint.x.toFixed(2);
660 var x = item.datapoint.x.toFixed(2);
661 var y = item.datapoint.y.toFixed(2);
661 var y = item.datapoint.y.toFixed(2);
662
662
663 if (!item.series.label){
663 if (!item.series.label){
664 item.series.label = 'commits';
664 item.series.label = 'commits';
665 }
665 }
666 var d = new Date(x*1000);
666 var d = new Date(x*1000);
667 var fd = d.toDateString()
667 var fd = d.toDateString()
668 var nr_commits = parseInt(y);
668 var nr_commits = parseInt(y);
669
669
670 var cur_data = dataset[item.series.label].data[item.dataIndex];
670 var cur_data = dataset[item.series.label].data[item.dataIndex];
671 var added = cur_data.added;
671 var added = cur_data.added;
672 var changed = cur_data.changed;
672 var changed = cur_data.changed;
673 var removed = cur_data.removed;
673 var removed = cur_data.removed;
674
674
675 var nr_commits_suffix = " ${_('commits')} ";
675 var nr_commits_suffix = " ${_('commits')} ";
676 var added_suffix = " ${_('files added')} ";
676 var added_suffix = " ${_('files added')} ";
677 var changed_suffix = " ${_('files changed')} ";
677 var changed_suffix = " ${_('files changed')} ";
678 var removed_suffix = " ${_('files removed')} ";
678 var removed_suffix = " ${_('files removed')} ";
679
679
680
680
681 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
681 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
682 if(added==1){added_suffix=" ${_('file added')} ";}
682 if(added==1){added_suffix=" ${_('file added')} ";}
683 if(changed==1){changed_suffix=" ${_('file changed')} ";}
683 if(changed==1){changed_suffix=" ${_('file changed')} ";}
684 if(removed==1){removed_suffix=" ${_('file removed')} ";}
684 if(removed==1){removed_suffix=" ${_('file removed')} ";}
685
685
686 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
686 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
687 +'<br/>'+
687 +'<br/>'+
688 nr_commits + nr_commits_suffix+'<br/>'+
688 nr_commits + nr_commits_suffix+'<br/>'+
689 added + added_suffix +'<br/>'+
689 added + added_suffix +'<br/>'+
690 changed + changed_suffix + '<br/>'+
690 changed + changed_suffix + '<br/>'+
691 removed + removed_suffix + '<br/>');
691 removed + removed_suffix + '<br/>');
692 }
692 }
693 }
693 }
694 else {
694 else {
695 var tooltip = YUD.get("tooltip");
695 var tooltip = YUD.get("tooltip");
696
696
697 if(tooltip) {
697 if(tooltip) {
698 tooltip.parentNode.removeChild(tooltip);
698 tooltip.parentNode.removeChild(tooltip);
699 }
699 }
700 previousPoint = null;
700 previousPoint = null;
701 }
701 }
702 }
702 }
703
703
704 /**
704 /**
705 * MAIN EXECUTION
705 * MAIN EXECUTION
706 */
706 */
707
707
708 var data = getDataAccordingToRanges(initial_ranges);
708 var data = getDataAccordingToRanges(initial_ranges);
709 generateCheckboxes(data);
709 generateCheckboxes(data);
710
710
711 //main plot
711 //main plot
712 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
712 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
713
713
714 //overview
714 //overview
715 var overview = YAHOO.widget.Flot(overviewContainer,
715 var overview = YAHOO.widget.Flot(overviewContainer,
716 overview_dataset, overview_options);
716 overview_dataset, overview_options);
717
717
718 //show initial selection on overview
718 //show initial selection on overview
719 overview.setSelection(initial_ranges);
719 overview.setSelection(initial_ranges);
720
720
721 plot.subscribe("plotselected", plotselected);
721 plot.subscribe("plotselected", plotselected);
722 plot.subscribe("plothover", plothover)
722 plot.subscribe("plothover", plothover)
723
723
724 overview.subscribe("plotselected", function (ranges) {
724 overview.subscribe("plotselected", function (ranges) {
725 plot.setSelection(ranges);
725 plot.setSelection(ranges);
726 });
726 });
727
727
728 // user choices on overview
728 // user choices on overview
729 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
729 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
730 }
730 }
731 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
731 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
732 </script>
732 </script>
733 %endif
733 %endif
734
734
735 </%def>
735 </%def>
General Comments 0
You need to be logged in to leave comments. Login now