##// END OF EJS Templates
quick-search: use smart group search when browsing inside a repository group....
marcink -
r2804:0f04cf5e default
parent child Browse files
Show More
@@ -1,413 +1,427 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import re
21 import re
22 import logging
22 import logging
23 import collections
23 import collections
24
24
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26
26
27 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps._base import BaseAppView
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator)
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator)
31 from rhodecode.lib.index import searcher_from_config
31 from rhodecode.lib.index import searcher_from_config
32 from rhodecode.lib.utils2 import safe_unicode, str2bool
32 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
33 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.ext_json import json
34 from rhodecode.model.db import (
34 from rhodecode.model.db import (
35 func, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
35 func, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
36 from rhodecode.model.repo import RepoModel
36 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo_group import RepoGroupModel
37 from rhodecode.model.repo_group import RepoGroupModel
38 from rhodecode.model.scm import RepoGroupList, RepoList
38 from rhodecode.model.scm import RepoGroupList, RepoList
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
40 from rhodecode.model.user_group import UserGroupModel
40 from rhodecode.model.user_group import UserGroupModel
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 class HomeView(BaseAppView):
45 class HomeView(BaseAppView):
46
46
47 def load_default_context(self):
47 def load_default_context(self):
48 c = self._get_local_tmpl_context()
48 c = self._get_local_tmpl_context()
49 c.user = c.auth_user.get_instance()
49 c.user = c.auth_user.get_instance()
50
50
51 return c
51 return c
52
52
53 @LoginRequired()
53 @LoginRequired()
54 @view_config(
54 @view_config(
55 route_name='user_autocomplete_data', request_method='GET',
55 route_name='user_autocomplete_data', request_method='GET',
56 renderer='json_ext', xhr=True)
56 renderer='json_ext', xhr=True)
57 def user_autocomplete_data(self):
57 def user_autocomplete_data(self):
58 self.load_default_context()
58 self.load_default_context()
59 query = self.request.GET.get('query')
59 query = self.request.GET.get('query')
60 active = str2bool(self.request.GET.get('active') or True)
60 active = str2bool(self.request.GET.get('active') or True)
61 include_groups = str2bool(self.request.GET.get('user_groups'))
61 include_groups = str2bool(self.request.GET.get('user_groups'))
62 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
62 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
63 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
63 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
64
64
65 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
65 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
66 query, active, include_groups)
66 query, active, include_groups)
67
67
68 _users = UserModel().get_users(
68 _users = UserModel().get_users(
69 name_contains=query, only_active=active)
69 name_contains=query, only_active=active)
70
70
71 def maybe_skip_default_user(usr):
71 def maybe_skip_default_user(usr):
72 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
72 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
73 return False
73 return False
74 return True
74 return True
75 _users = filter(maybe_skip_default_user, _users)
75 _users = filter(maybe_skip_default_user, _users)
76
76
77 if include_groups:
77 if include_groups:
78 # extend with user groups
78 # extend with user groups
79 _user_groups = UserGroupModel().get_user_groups(
79 _user_groups = UserGroupModel().get_user_groups(
80 name_contains=query, only_active=active,
80 name_contains=query, only_active=active,
81 expand_groups=expand_groups)
81 expand_groups=expand_groups)
82 _users = _users + _user_groups
82 _users = _users + _user_groups
83
83
84 return {'suggestions': _users}
84 return {'suggestions': _users}
85
85
86 @LoginRequired()
86 @LoginRequired()
87 @NotAnonymous()
87 @NotAnonymous()
88 @view_config(
88 @view_config(
89 route_name='user_group_autocomplete_data', request_method='GET',
89 route_name='user_group_autocomplete_data', request_method='GET',
90 renderer='json_ext', xhr=True)
90 renderer='json_ext', xhr=True)
91 def user_group_autocomplete_data(self):
91 def user_group_autocomplete_data(self):
92 self.load_default_context()
92 self.load_default_context()
93 query = self.request.GET.get('query')
93 query = self.request.GET.get('query')
94 active = str2bool(self.request.GET.get('active') or True)
94 active = str2bool(self.request.GET.get('active') or True)
95 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
95 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
96
96
97 log.debug('generating user group list, query:%s, active:%s',
97 log.debug('generating user group list, query:%s, active:%s',
98 query, active)
98 query, active)
99
99
100 _user_groups = UserGroupModel().get_user_groups(
100 _user_groups = UserGroupModel().get_user_groups(
101 name_contains=query, only_active=active,
101 name_contains=query, only_active=active,
102 expand_groups=expand_groups)
102 expand_groups=expand_groups)
103 _user_groups = _user_groups
103 _user_groups = _user_groups
104
104
105 return {'suggestions': _user_groups}
105 return {'suggestions': _user_groups}
106
106
107 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
107 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
108 org_query = name_contains
108 org_query = name_contains
109 allowed_ids = self._rhodecode_user.repo_acl_ids(
109 allowed_ids = self._rhodecode_user.repo_acl_ids(
110 ['repository.read', 'repository.write', 'repository.admin'],
110 ['repository.read', 'repository.write', 'repository.admin'],
111 cache=False, name_filter=name_contains) or [-1]
111 cache=False, name_filter=name_contains) or [-1]
112
112
113 query = Repository.query()\
113 query = Repository.query()\
114 .order_by(func.length(Repository.repo_name))\
114 .order_by(func.length(Repository.repo_name))\
115 .order_by(Repository.repo_name)\
115 .order_by(Repository.repo_name)\
116 .filter(or_(
116 .filter(or_(
117 # generate multiple IN to fix limitation problems
117 # generate multiple IN to fix limitation problems
118 *in_filter_generator(Repository.repo_id, allowed_ids)
118 *in_filter_generator(Repository.repo_id, allowed_ids)
119 ))
119 ))
120
120
121 if repo_type:
121 if repo_type:
122 query = query.filter(Repository.repo_type == repo_type)
122 query = query.filter(Repository.repo_type == repo_type)
123
123
124 if name_contains:
124 if name_contains:
125 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
125 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
126 query = query.filter(
126 query = query.filter(
127 Repository.repo_name.ilike(ilike_expression))
127 Repository.repo_name.ilike(ilike_expression))
128 query = query.limit(limit)
128 query = query.limit(limit)
129
129
130 acl_iter = query
130 acl_iter = query
131
131
132 return [
132 return [
133 {
133 {
134 'id': obj.repo_name,
134 'id': obj.repo_name,
135 'value': org_query,
135 'value': org_query,
136 'value_display': obj.repo_name,
136 'value_display': obj.repo_name,
137 'text': obj.repo_name,
137 'text': obj.repo_name,
138 'type': 'repo',
138 'type': 'repo',
139 'repo_id': obj.repo_id,
139 'repo_id': obj.repo_id,
140 'repo_type': obj.repo_type,
140 'repo_type': obj.repo_type,
141 'private': obj.private,
141 'private': obj.private,
142 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
142 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
143 }
143 }
144 for obj in acl_iter]
144 for obj in acl_iter]
145
145
146 def _get_repo_group_list(self, name_contains=None, limit=20):
146 def _get_repo_group_list(self, name_contains=None, limit=20):
147 org_query = name_contains
147 org_query = name_contains
148 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
148 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
149 ['group.read', 'group.write', 'group.admin'],
149 ['group.read', 'group.write', 'group.admin'],
150 cache=False, name_filter=name_contains) or [-1]
150 cache=False, name_filter=name_contains) or [-1]
151
151
152 query = RepoGroup.query()\
152 query = RepoGroup.query()\
153 .order_by(func.length(RepoGroup.group_name))\
153 .order_by(func.length(RepoGroup.group_name))\
154 .order_by(RepoGroup.group_name) \
154 .order_by(RepoGroup.group_name) \
155 .filter(or_(
155 .filter(or_(
156 # generate multiple IN to fix limitation problems
156 # generate multiple IN to fix limitation problems
157 *in_filter_generator(RepoGroup.group_id, allowed_ids)
157 *in_filter_generator(RepoGroup.group_id, allowed_ids)
158 ))
158 ))
159
159
160 if name_contains:
160 if name_contains:
161 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
161 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
162 query = query.filter(
162 query = query.filter(
163 RepoGroup.group_name.ilike(ilike_expression))
163 RepoGroup.group_name.ilike(ilike_expression))
164 query = query.limit(limit)
164 query = query.limit(limit)
165
165
166 acl_iter = query
166 acl_iter = query
167
167
168 return [
168 return [
169 {
169 {
170 'id': obj.group_name,
170 'id': obj.group_name,
171 'value': org_query,
171 'value': org_query,
172 'value_display': obj.group_name,
172 'value_display': obj.group_name,
173 'type': 'repo_group',
173 'type': 'repo_group',
174 'url': h.route_path(
174 'url': h.route_path(
175 'repo_group_home', repo_group_name=obj.group_name)
175 'repo_group_home', repo_group_name=obj.group_name)
176 }
176 }
177 for obj in acl_iter]
177 for obj in acl_iter]
178
178
179 def _get_user_list(self, name_contains=None, limit=20):
179 def _get_user_list(self, name_contains=None, limit=20):
180 org_query = name_contains
180 org_query = name_contains
181 if not name_contains:
181 if not name_contains:
182 return []
182 return []
183
183
184 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
184 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
185 if len(name_contains) != 1:
185 if len(name_contains) != 1:
186 return []
186 return []
187 name_contains = name_contains[0]
187 name_contains = name_contains[0]
188
188
189 query = User.query()\
189 query = User.query()\
190 .order_by(func.length(User.username))\
190 .order_by(func.length(User.username))\
191 .order_by(User.username) \
191 .order_by(User.username) \
192 .filter(User.username != User.DEFAULT_USER)
192 .filter(User.username != User.DEFAULT_USER)
193
193
194 if name_contains:
194 if name_contains:
195 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
195 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
196 query = query.filter(
196 query = query.filter(
197 User.username.ilike(ilike_expression))
197 User.username.ilike(ilike_expression))
198 query = query.limit(limit)
198 query = query.limit(limit)
199
199
200 acl_iter = query
200 acl_iter = query
201
201
202 return [
202 return [
203 {
203 {
204 'id': obj.user_id,
204 'id': obj.user_id,
205 'value': org_query,
205 'value': org_query,
206 'value_display': obj.username,
206 'value_display': obj.username,
207 'type': 'user',
207 'type': 'user',
208 'icon_link': h.gravatar_url(obj.email, 30),
208 'icon_link': h.gravatar_url(obj.email, 30),
209 'url': h.route_path(
209 'url': h.route_path(
210 'user_profile', username=obj.username)
210 'user_profile', username=obj.username)
211 }
211 }
212 for obj in acl_iter]
212 for obj in acl_iter]
213
213
214 def _get_user_groups_list(self, name_contains=None, limit=20):
214 def _get_user_groups_list(self, name_contains=None, limit=20):
215 org_query = name_contains
215 org_query = name_contains
216 if not name_contains:
216 if not name_contains:
217 return []
217 return []
218
218
219 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
219 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
220 if len(name_contains) != 1:
220 if len(name_contains) != 1:
221 return []
221 return []
222 name_contains = name_contains[0]
222 name_contains = name_contains[0]
223
223
224 query = UserGroup.query()\
224 query = UserGroup.query()\
225 .order_by(func.length(UserGroup.users_group_name))\
225 .order_by(func.length(UserGroup.users_group_name))\
226 .order_by(UserGroup.users_group_name)
226 .order_by(UserGroup.users_group_name)
227
227
228 if name_contains:
228 if name_contains:
229 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
229 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
230 query = query.filter(
230 query = query.filter(
231 UserGroup.users_group_name.ilike(ilike_expression))
231 UserGroup.users_group_name.ilike(ilike_expression))
232 query = query.limit(limit)
232 query = query.limit(limit)
233
233
234 acl_iter = query
234 acl_iter = query
235
235
236 return [
236 return [
237 {
237 {
238 'id': obj.users_group_id,
238 'id': obj.users_group_id,
239 'value': org_query,
239 'value': org_query,
240 'value_display': obj.users_group_name,
240 'value_display': obj.users_group_name,
241 'type': 'user_group',
241 'type': 'user_group',
242 'url': h.route_path(
242 'url': h.route_path(
243 'user_group_profile', user_group_name=obj.users_group_name)
243 'user_group_profile', user_group_name=obj.users_group_name)
244 }
244 }
245 for obj in acl_iter]
245 for obj in acl_iter]
246
246
247 def _get_hash_commit_list(self, auth_user, query):
247 def _get_hash_commit_list(self, auth_user, query):
248 org_query = query
248 org_query = query
249 if not query or len(query) < 3:
249 if not query or len(query) < 3:
250 return []
250 return []
251
251
252 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
252 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
253
253
254 if len(commit_hashes) != 1:
254 if len(commit_hashes) != 1:
255 return []
255 return []
256 commit_hash = commit_hashes[0]
256 commit_hash = commit_hashes[0]
257
257
258 searcher = searcher_from_config(self.request.registry.settings)
258 searcher = searcher_from_config(self.request.registry.settings)
259 result = searcher.search(
259 result = searcher.search(
260 'commit_id:%s*' % commit_hash, 'commit', auth_user,
260 'commit_id:%s*' % commit_hash, 'commit', auth_user,
261 raise_on_exc=False)
261 raise_on_exc=False)
262
262
263 return [
263 return [
264 {
264 {
265 'id': entry['commit_id'],
265 'id': entry['commit_id'],
266 'value': org_query,
266 'value': org_query,
267 'value_display': 'repo `{}` commit: {}'.format(
267 'value_display': 'repo `{}` commit: {}'.format(
268 entry['repository'], entry['commit_id']),
268 entry['repository'], entry['commit_id']),
269 'type': 'commit',
269 'type': 'commit',
270 'repo': entry['repository'],
270 'repo': entry['repository'],
271 'url': h.route_path(
271 'url': h.route_path(
272 'repo_commit',
272 'repo_commit',
273 repo_name=entry['repository'], commit_id=entry['commit_id'])
273 repo_name=entry['repository'], commit_id=entry['commit_id'])
274 }
274 }
275 for entry in result['results']]
275 for entry in result['results']]
276
276
277 @LoginRequired()
277 @LoginRequired()
278 @view_config(
278 @view_config(
279 route_name='repo_list_data', request_method='GET',
279 route_name='repo_list_data', request_method='GET',
280 renderer='json_ext', xhr=True)
280 renderer='json_ext', xhr=True)
281 def repo_list_data(self):
281 def repo_list_data(self):
282 _ = self.request.translate
282 _ = self.request.translate
283 self.load_default_context()
283 self.load_default_context()
284
284
285 query = self.request.GET.get('query')
285 query = self.request.GET.get('query')
286 repo_type = self.request.GET.get('repo_type')
286 repo_type = self.request.GET.get('repo_type')
287 log.debug('generating repo list, query:%s, repo_type:%s',
287 log.debug('generating repo list, query:%s, repo_type:%s',
288 query, repo_type)
288 query, repo_type)
289
289
290 res = []
290 res = []
291 repos = self._get_repo_list(query, repo_type=repo_type)
291 repos = self._get_repo_list(query, repo_type=repo_type)
292 if repos:
292 if repos:
293 res.append({
293 res.append({
294 'text': _('Repositories'),
294 'text': _('Repositories'),
295 'children': repos
295 'children': repos
296 })
296 })
297
297
298 data = {
298 data = {
299 'more': False,
299 'more': False,
300 'results': res
300 'results': res
301 }
301 }
302 return data
302 return data
303
303
304 @LoginRequired()
304 @LoginRequired()
305 @view_config(
305 @view_config(
306 route_name='goto_switcher_data', request_method='GET',
306 route_name='goto_switcher_data', request_method='GET',
307 renderer='json_ext', xhr=True)
307 renderer='json_ext', xhr=True)
308 def goto_switcher_data(self):
308 def goto_switcher_data(self):
309 c = self.load_default_context()
309 c = self.load_default_context()
310
310
311 _ = self.request.translate
311 _ = self.request.translate
312
312
313 query = self.request.GET.get('query')
313 query = self.request.GET.get('query')
314 log.debug('generating main filter data, query %s', query)
314 log.debug('generating main filter data, query %s', query)
315
315
316 default_search_val = u'Full text search for: `{}`'.format(query)
316 default_search_val = u'Full text search for: `{}`'.format(query)
317 res = []
317 res = []
318 if not query:
318 if not query:
319 return {'suggestions': res}
319 return {'suggestions': res}
320
320
321 res.append({
321 res.append({
322 'id': -1,
322 'id': -1,
323 'value': query,
323 'value': query,
324 'value_display': default_search_val,
324 'value_display': default_search_val,
325 'type': 'search',
325 'type': 'search',
326 'url': h.route_path(
326 'url': h.route_path(
327 'search', _query={'q': query})
327 'search', _query={'q': query})
328 })
328 })
329 repo_group_id = safe_int(self.request.GET.get('repo_group_id'))
330 if repo_group_id:
331 repo_group = RepoGroup.get(repo_group_id)
332 composed_hint = '{}/{}'.format(repo_group.group_name, query)
333 show_hint = not query.startswith(repo_group.group_name)
334 if repo_group and show_hint:
335 hint = u'Group search: `{}`'.format(composed_hint)
336 res.append({
337 'id': -1,
338 'value': composed_hint,
339 'value_display': hint,
340 'type': 'hint',
341 'url': ""
342 })
329
343
330 repo_groups = self._get_repo_group_list(query)
344 repo_groups = self._get_repo_group_list(query)
331 for serialized_repo_group in repo_groups:
345 for serialized_repo_group in repo_groups:
332 res.append(serialized_repo_group)
346 res.append(serialized_repo_group)
333
347
334 repos = self._get_repo_list(query)
348 repos = self._get_repo_list(query)
335 for serialized_repo in repos:
349 for serialized_repo in repos:
336 res.append(serialized_repo)
350 res.append(serialized_repo)
337
351
338 # TODO(marcink): permissions for that ?
352 # TODO(marcink): permissions for that ?
339 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
353 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
340 if allowed_user_search:
354 if allowed_user_search:
341 users = self._get_user_list(query)
355 users = self._get_user_list(query)
342 for serialized_user in users:
356 for serialized_user in users:
343 res.append(serialized_user)
357 res.append(serialized_user)
344
358
345 user_groups = self._get_user_groups_list(query)
359 user_groups = self._get_user_groups_list(query)
346 for serialized_user_group in user_groups:
360 for serialized_user_group in user_groups:
347 res.append(serialized_user_group)
361 res.append(serialized_user_group)
348
362
349 commits = self._get_hash_commit_list(c.auth_user, query)
363 commits = self._get_hash_commit_list(c.auth_user, query)
350 if commits:
364 if commits:
351 unique_repos = collections.OrderedDict()
365 unique_repos = collections.OrderedDict()
352 for commit in commits:
366 for commit in commits:
353 repo_name = commit['repo']
367 repo_name = commit['repo']
354 unique_repos.setdefault(repo_name, []).append(commit)
368 unique_repos.setdefault(repo_name, []).append(commit)
355
369
356 for repo, commits in unique_repos.items():
370 for repo, commits in unique_repos.items():
357 for commit in commits:
371 for commit in commits:
358 res.append(commit)
372 res.append(commit)
359
373
360 return {'suggestions': res}
374 return {'suggestions': res}
361
375
362 def _get_groups_and_repos(self, repo_group_id=None):
376 def _get_groups_and_repos(self, repo_group_id=None):
363 # repo groups groups
377 # repo groups groups
364 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
378 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
365 _perms = ['group.read', 'group.write', 'group.admin']
379 _perms = ['group.read', 'group.write', 'group.admin']
366 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
380 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
367 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
381 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
368 repo_group_list=repo_group_list_acl, admin=False)
382 repo_group_list=repo_group_list_acl, admin=False)
369
383
370 # repositories
384 # repositories
371 repo_list = Repository.get_all_repos(group_id=repo_group_id)
385 repo_list = Repository.get_all_repos(group_id=repo_group_id)
372 _perms = ['repository.read', 'repository.write', 'repository.admin']
386 _perms = ['repository.read', 'repository.write', 'repository.admin']
373 repo_list_acl = RepoList(repo_list, perm_set=_perms)
387 repo_list_acl = RepoList(repo_list, perm_set=_perms)
374 repo_data = RepoModel().get_repos_as_dict(
388 repo_data = RepoModel().get_repos_as_dict(
375 repo_list=repo_list_acl, admin=False)
389 repo_list=repo_list_acl, admin=False)
376
390
377 return repo_data, repo_group_data
391 return repo_data, repo_group_data
378
392
379 @LoginRequired()
393 @LoginRequired()
380 @view_config(
394 @view_config(
381 route_name='home', request_method='GET',
395 route_name='home', request_method='GET',
382 renderer='rhodecode:templates/index.mako')
396 renderer='rhodecode:templates/index.mako')
383 def main_page(self):
397 def main_page(self):
384 c = self.load_default_context()
398 c = self.load_default_context()
385 c.repo_group = None
399 c.repo_group = None
386
400
387 repo_data, repo_group_data = self._get_groups_and_repos()
401 repo_data, repo_group_data = self._get_groups_and_repos()
388 # json used to render the grids
402 # json used to render the grids
389 c.repos_data = json.dumps(repo_data)
403 c.repos_data = json.dumps(repo_data)
390 c.repo_groups_data = json.dumps(repo_group_data)
404 c.repo_groups_data = json.dumps(repo_group_data)
391
405
392 return self._get_template_context(c)
406 return self._get_template_context(c)
393
407
394 @LoginRequired()
408 @LoginRequired()
395 @HasRepoGroupPermissionAnyDecorator(
409 @HasRepoGroupPermissionAnyDecorator(
396 'group.read', 'group.write', 'group.admin')
410 'group.read', 'group.write', 'group.admin')
397 @view_config(
411 @view_config(
398 route_name='repo_group_home', request_method='GET',
412 route_name='repo_group_home', request_method='GET',
399 renderer='rhodecode:templates/index_repo_group.mako')
413 renderer='rhodecode:templates/index_repo_group.mako')
400 @view_config(
414 @view_config(
401 route_name='repo_group_home_slash', request_method='GET',
415 route_name='repo_group_home_slash', request_method='GET',
402 renderer='rhodecode:templates/index_repo_group.mako')
416 renderer='rhodecode:templates/index_repo_group.mako')
403 def repo_group_main_page(self):
417 def repo_group_main_page(self):
404 c = self.load_default_context()
418 c = self.load_default_context()
405 c.repo_group = self.request.db_repo_group
419 c.repo_group = self.request.db_repo_group
406 repo_data, repo_group_data = self._get_groups_and_repos(
420 repo_data, repo_group_data = self._get_groups_and_repos(
407 c.repo_group.group_id)
421 c.repo_group.group_id)
408
422
409 # json used to render the grids
423 # json used to render the grids
410 c.repos_data = json.dumps(repo_data)
424 c.repos_data = json.dumps(repo_data)
411 c.repo_groups_data = json.dumps(repo_group_data)
425 c.repo_groups_data = json.dumps(repo_group_data)
412
426
413 return self._get_template_context(c)
427 return self._get_template_context(c)
@@ -1,667 +1,676 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <%include file="/ejs_templates/templates.html"/>
4 <%include file="/ejs_templates/templates.html"/>
5
5
6 <div class="outerwrapper">
6 <div class="outerwrapper">
7 <!-- HEADER -->
7 <!-- HEADER -->
8 <div class="header">
8 <div class="header">
9 <div id="header-inner" class="wrapper">
9 <div id="header-inner" class="wrapper">
10 <div id="logo">
10 <div id="logo">
11 <div class="logo-wrapper">
11 <div class="logo-wrapper">
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
13 </div>
13 </div>
14 %if c.rhodecode_name:
14 %if c.rhodecode_name:
15 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
15 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
16 %endif
16 %endif
17 </div>
17 </div>
18 <!-- MENU BAR NAV -->
18 <!-- MENU BAR NAV -->
19 ${self.menu_bar_nav()}
19 ${self.menu_bar_nav()}
20 <!-- END MENU BAR NAV -->
20 <!-- END MENU BAR NAV -->
21 </div>
21 </div>
22 </div>
22 </div>
23 ${self.menu_bar_subnav()}
23 ${self.menu_bar_subnav()}
24 <!-- END HEADER -->
24 <!-- END HEADER -->
25
25
26 <!-- CONTENT -->
26 <!-- CONTENT -->
27 <div id="content" class="wrapper">
27 <div id="content" class="wrapper">
28
28
29 <rhodecode-toast id="notifications"></rhodecode-toast>
29 <rhodecode-toast id="notifications"></rhodecode-toast>
30
30
31 <div class="main">
31 <div class="main">
32 ${next.main()}
32 ${next.main()}
33 </div>
33 </div>
34 </div>
34 </div>
35 <!-- END CONTENT -->
35 <!-- END CONTENT -->
36
36
37 </div>
37 </div>
38 <!-- FOOTER -->
38 <!-- FOOTER -->
39 <div id="footer">
39 <div id="footer">
40 <div id="footer-inner" class="title wrapper">
40 <div id="footer-inner" class="title wrapper">
41 <div>
41 <div>
42 <p class="footer-link-right">
42 <p class="footer-link-right">
43 % if c.visual.show_version:
43 % if c.visual.show_version:
44 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
44 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
45 % endif
45 % endif
46 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
46 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
47 % if c.visual.rhodecode_support_url:
47 % if c.visual.rhodecode_support_url:
48 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
48 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
49 % endif
49 % endif
50 </p>
50 </p>
51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
52 <p class="server-instance" style="display:${sid}">
52 <p class="server-instance" style="display:${sid}">
53 ## display hidden instance ID if specially defined
53 ## display hidden instance ID if specially defined
54 % if c.rhodecode_instanceid:
54 % if c.rhodecode_instanceid:
55 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
55 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
56 % endif
56 % endif
57 </p>
57 </p>
58 </div>
58 </div>
59 </div>
59 </div>
60 </div>
60 </div>
61
61
62 <!-- END FOOTER -->
62 <!-- END FOOTER -->
63
63
64 ### MAKO DEFS ###
64 ### MAKO DEFS ###
65
65
66 <%def name="menu_bar_subnav()">
66 <%def name="menu_bar_subnav()">
67 </%def>
67 </%def>
68
68
69 <%def name="breadcrumbs(class_='breadcrumbs')">
69 <%def name="breadcrumbs(class_='breadcrumbs')">
70 <div class="${class_}">
70 <div class="${class_}">
71 ${self.breadcrumbs_links()}
71 ${self.breadcrumbs_links()}
72 </div>
72 </div>
73 </%def>
73 </%def>
74
74
75 <%def name="admin_menu()">
75 <%def name="admin_menu()">
76 <ul class="admin_menu submenu">
76 <ul class="admin_menu submenu">
77 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
77 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
78 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
78 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
79 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
79 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
80 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
80 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
81 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
81 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
82 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
82 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
83 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
83 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
84 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
84 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
85 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
85 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
86 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
86 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
87 </ul>
87 </ul>
88 </%def>
88 </%def>
89
89
90
90
91 <%def name="dt_info_panel(elements)">
91 <%def name="dt_info_panel(elements)">
92 <dl class="dl-horizontal">
92 <dl class="dl-horizontal">
93 %for dt, dd, title, show_items in elements:
93 %for dt, dd, title, show_items in elements:
94 <dt>${dt}:</dt>
94 <dt>${dt}:</dt>
95 <dd title="${h.tooltip(title)}">
95 <dd title="${h.tooltip(title)}">
96 %if callable(dd):
96 %if callable(dd):
97 ## allow lazy evaluation of elements
97 ## allow lazy evaluation of elements
98 ${dd()}
98 ${dd()}
99 %else:
99 %else:
100 ${dd}
100 ${dd}
101 %endif
101 %endif
102 %if show_items:
102 %if show_items:
103 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
103 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
104 %endif
104 %endif
105 </dd>
105 </dd>
106
106
107 %if show_items:
107 %if show_items:
108 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
108 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
109 %for item in show_items:
109 %for item in show_items:
110 <dt></dt>
110 <dt></dt>
111 <dd>${item}</dd>
111 <dd>${item}</dd>
112 %endfor
112 %endfor
113 </div>
113 </div>
114 %endif
114 %endif
115
115
116 %endfor
116 %endfor
117 </dl>
117 </dl>
118 </%def>
118 </%def>
119
119
120
120
121 <%def name="gravatar(email, size=16)">
121 <%def name="gravatar(email, size=16)">
122 <%
122 <%
123 if (size > 16):
123 if (size > 16):
124 gravatar_class = 'gravatar gravatar-large'
124 gravatar_class = 'gravatar gravatar-large'
125 else:
125 else:
126 gravatar_class = 'gravatar'
126 gravatar_class = 'gravatar'
127 %>
127 %>
128 <%doc>
128 <%doc>
129 TODO: johbo: For now we serve double size images to make it smooth
129 TODO: johbo: For now we serve double size images to make it smooth
130 for retina. This is how it worked until now. Should be replaced
130 for retina. This is how it worked until now. Should be replaced
131 with a better solution at some point.
131 with a better solution at some point.
132 </%doc>
132 </%doc>
133 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
133 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
134 </%def>
134 </%def>
135
135
136
136
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
138 <% email = h.email_or_none(contact) %>
138 <% email = h.email_or_none(contact) %>
139 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
139 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
140 ${self.gravatar(email, size)}
140 ${self.gravatar(email, size)}
141 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
141 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
142 </div>
142 </div>
143 </%def>
143 </%def>
144
144
145
145
146 ## admin menu used for people that have some admin resources
146 ## admin menu used for people that have some admin resources
147 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
147 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
148 <ul class="submenu">
148 <ul class="submenu">
149 %if repositories:
149 %if repositories:
150 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
150 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
151 %endif
151 %endif
152 %if repository_groups:
152 %if repository_groups:
153 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
153 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
154 %endif
154 %endif
155 %if user_groups:
155 %if user_groups:
156 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
156 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
157 %endif
157 %endif
158 </ul>
158 </ul>
159 </%def>
159 </%def>
160
160
161 <%def name="repo_page_title(repo_instance)">
161 <%def name="repo_page_title(repo_instance)">
162 <div class="title-content">
162 <div class="title-content">
163 <div class="title-main">
163 <div class="title-main">
164 ## SVN/HG/GIT icons
164 ## SVN/HG/GIT icons
165 %if h.is_hg(repo_instance):
165 %if h.is_hg(repo_instance):
166 <i class="icon-hg"></i>
166 <i class="icon-hg"></i>
167 %endif
167 %endif
168 %if h.is_git(repo_instance):
168 %if h.is_git(repo_instance):
169 <i class="icon-git"></i>
169 <i class="icon-git"></i>
170 %endif
170 %endif
171 %if h.is_svn(repo_instance):
171 %if h.is_svn(repo_instance):
172 <i class="icon-svn"></i>
172 <i class="icon-svn"></i>
173 %endif
173 %endif
174
174
175 ## public/private
175 ## public/private
176 %if repo_instance.private:
176 %if repo_instance.private:
177 <i class="icon-repo-private"></i>
177 <i class="icon-repo-private"></i>
178 %else:
178 %else:
179 <i class="icon-repo-public"></i>
179 <i class="icon-repo-public"></i>
180 %endif
180 %endif
181
181
182 ## repo name with group name
182 ## repo name with group name
183 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
183 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
184
184
185 </div>
185 </div>
186
186
187 ## FORKED
187 ## FORKED
188 %if repo_instance.fork:
188 %if repo_instance.fork:
189 <p>
189 <p>
190 <i class="icon-code-fork"></i> ${_('Fork of')}
190 <i class="icon-code-fork"></i> ${_('Fork of')}
191 <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
191 <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
192 </p>
192 </p>
193 %endif
193 %endif
194
194
195 ## IMPORTED FROM REMOTE
195 ## IMPORTED FROM REMOTE
196 %if repo_instance.clone_uri:
196 %if repo_instance.clone_uri:
197 <p>
197 <p>
198 <i class="icon-code-fork"></i> ${_('Clone from')}
198 <i class="icon-code-fork"></i> ${_('Clone from')}
199 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
199 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
200 </p>
200 </p>
201 %endif
201 %endif
202
202
203 ## LOCKING STATUS
203 ## LOCKING STATUS
204 %if repo_instance.locked[0]:
204 %if repo_instance.locked[0]:
205 <p class="locking_locked">
205 <p class="locking_locked">
206 <i class="icon-repo-lock"></i>
206 <i class="icon-repo-lock"></i>
207 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
207 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
208 </p>
208 </p>
209 %elif repo_instance.enable_locking:
209 %elif repo_instance.enable_locking:
210 <p class="locking_unlocked">
210 <p class="locking_unlocked">
211 <i class="icon-repo-unlock"></i>
211 <i class="icon-repo-unlock"></i>
212 ${_('Repository not locked. Pull repository to lock it.')}
212 ${_('Repository not locked. Pull repository to lock it.')}
213 </p>
213 </p>
214 %endif
214 %endif
215
215
216 </div>
216 </div>
217 </%def>
217 </%def>
218
218
219 <%def name="repo_menu(active=None)">
219 <%def name="repo_menu(active=None)">
220 <%
220 <%
221 def is_active(selected):
221 def is_active(selected):
222 if selected == active:
222 if selected == active:
223 return "active"
223 return "active"
224 %>
224 %>
225
225
226 <!--- CONTEXT BAR -->
226 <!--- CONTEXT BAR -->
227 <div id="context-bar">
227 <div id="context-bar">
228 <div class="wrapper">
228 <div class="wrapper">
229 <ul id="context-pages" class="navigation horizontal-list">
229 <ul id="context-pages" class="navigation horizontal-list">
230 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
230 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
231 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
231 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
232 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
232 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
233 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
233 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
236 <li class="${is_active('showpullrequest')}">
236 <li class="${is_active('showpullrequest')}">
237 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
237 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
238 %if c.repository_pull_requests:
238 %if c.repository_pull_requests:
239 <span class="pr_notifications">${c.repository_pull_requests}</span>
239 <span class="pr_notifications">${c.repository_pull_requests}</span>
240 %endif
240 %endif
241 <div class="menulabel">${_('Pull Requests')}</div>
241 <div class="menulabel">${_('Pull Requests')}</div>
242 </a>
242 </a>
243 </li>
243 </li>
244 %endif
244 %endif
245 <li class="${is_active('options')}">
245 <li class="${is_active('options')}">
246 <a class="menulink dropdown">
246 <a class="menulink dropdown">
247 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
247 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
248 </a>
248 </a>
249 <ul class="submenu">
249 <ul class="submenu">
250 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
250 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
251 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
251 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
252 %endif
252 %endif
253 %if c.rhodecode_db_repo.fork:
253 %if c.rhodecode_db_repo.fork:
254 <li>
254 <li>
255 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
255 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
256 href="${h.route_path('repo_compare',
256 href="${h.route_path('repo_compare',
257 repo_name=c.rhodecode_db_repo.fork.repo_name,
257 repo_name=c.rhodecode_db_repo.fork.repo_name,
258 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
258 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
259 source_ref=c.rhodecode_db_repo.landing_rev[1],
259 source_ref=c.rhodecode_db_repo.landing_rev[1],
260 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
260 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
261 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
261 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
262 _query=dict(merge=1))}"
262 _query=dict(merge=1))}"
263 >
263 >
264 ${_('Compare fork')}
264 ${_('Compare fork')}
265 </a>
265 </a>
266 </li>
266 </li>
267 %endif
267 %endif
268
268
269 <li><a href="${h.route_path('search_repo',repo_name=c.repo_name)}">${_('Search')}</a></li>
269 <li><a href="${h.route_path('search_repo',repo_name=c.repo_name)}">${_('Search')}</a></li>
270
270
271 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
271 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
272 %if c.rhodecode_db_repo.locked[0]:
272 %if c.rhodecode_db_repo.locked[0]:
273 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
273 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
274 %else:
274 %else:
275 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
275 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
276 %endif
276 %endif
277 %endif
277 %endif
278 %if c.rhodecode_user.username != h.DEFAULT_USER:
278 %if c.rhodecode_user.username != h.DEFAULT_USER:
279 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
279 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
280 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
280 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
281 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
281 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
282 %endif
282 %endif
283 %endif
283 %endif
284 </ul>
284 </ul>
285 </li>
285 </li>
286 </ul>
286 </ul>
287 </div>
287 </div>
288 <div class="clear"></div>
288 <div class="clear"></div>
289 </div>
289 </div>
290 <!--- END CONTEXT BAR -->
290 <!--- END CONTEXT BAR -->
291
291
292 </%def>
292 </%def>
293
293
294 <%def name="usermenu(active=False)">
294 <%def name="usermenu(active=False)">
295 ## USER MENU
295 ## USER MENU
296 <li id="quick_login_li" class="${'active' if active else ''}">
296 <li id="quick_login_li" class="${'active' if active else ''}">
297 <a id="quick_login_link" class="menulink childs">
297 <a id="quick_login_link" class="menulink childs">
298 ${gravatar(c.rhodecode_user.email, 20)}
298 ${gravatar(c.rhodecode_user.email, 20)}
299 <span class="user">
299 <span class="user">
300 %if c.rhodecode_user.username != h.DEFAULT_USER:
300 %if c.rhodecode_user.username != h.DEFAULT_USER:
301 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
301 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
302 %else:
302 %else:
303 <span>${_('Sign in')}</span>
303 <span>${_('Sign in')}</span>
304 %endif
304 %endif
305 </span>
305 </span>
306 </a>
306 </a>
307
307
308 <div class="user-menu submenu">
308 <div class="user-menu submenu">
309 <div id="quick_login">
309 <div id="quick_login">
310 %if c.rhodecode_user.username == h.DEFAULT_USER:
310 %if c.rhodecode_user.username == h.DEFAULT_USER:
311 <h4>${_('Sign in to your account')}</h4>
311 <h4>${_('Sign in to your account')}</h4>
312 ${h.form(h.route_path('login', _query={'came_from': h.current_route_path(request)}), needs_csrf_token=False)}
312 ${h.form(h.route_path('login', _query={'came_from': h.current_route_path(request)}), needs_csrf_token=False)}
313 <div class="form form-vertical">
313 <div class="form form-vertical">
314 <div class="fields">
314 <div class="fields">
315 <div class="field">
315 <div class="field">
316 <div class="label">
316 <div class="label">
317 <label for="username">${_('Username')}:</label>
317 <label for="username">${_('Username')}:</label>
318 </div>
318 </div>
319 <div class="input">
319 <div class="input">
320 ${h.text('username',class_='focus',tabindex=1)}
320 ${h.text('username',class_='focus',tabindex=1)}
321 </div>
321 </div>
322
322
323 </div>
323 </div>
324 <div class="field">
324 <div class="field">
325 <div class="label">
325 <div class="label">
326 <label for="password">${_('Password')}:</label>
326 <label for="password">${_('Password')}:</label>
327 %if h.HasPermissionAny('hg.password_reset.enabled')():
327 %if h.HasPermissionAny('hg.password_reset.enabled')():
328 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
328 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
329 %endif
329 %endif
330 </div>
330 </div>
331 <div class="input">
331 <div class="input">
332 ${h.password('password',class_='focus',tabindex=2)}
332 ${h.password('password',class_='focus',tabindex=2)}
333 </div>
333 </div>
334 </div>
334 </div>
335 <div class="buttons">
335 <div class="buttons">
336 <div class="register">
336 <div class="register">
337 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
337 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
338 ${h.link_to(_("Don't have an account?"),h.route_path('register'))} <br/>
338 ${h.link_to(_("Don't have an account?"),h.route_path('register'))} <br/>
339 %endif
339 %endif
340 ${h.link_to(_("Using external auth? Sign In here."),h.route_path('login'))}
340 ${h.link_to(_("Using external auth? Sign In here."),h.route_path('login'))}
341 </div>
341 </div>
342 <div class="submit">
342 <div class="submit">
343 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
343 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
344 </div>
344 </div>
345 </div>
345 </div>
346 </div>
346 </div>
347 </div>
347 </div>
348 ${h.end_form()}
348 ${h.end_form()}
349 %else:
349 %else:
350 <div class="">
350 <div class="">
351 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
351 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
352 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
352 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
353 <div class="email">${c.rhodecode_user.email}</div>
353 <div class="email">${c.rhodecode_user.email}</div>
354 </div>
354 </div>
355 <div class="">
355 <div class="">
356 <ol class="links">
356 <ol class="links">
357 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
357 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
358 % if c.rhodecode_user.personal_repo_group:
358 % if c.rhodecode_user.personal_repo_group:
359 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
359 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
360 % endif
360 % endif
361 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
361 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
362
362
363 <li class="logout">
363 <li class="logout">
364 ${h.secure_form(h.route_path('logout'), request=request)}
364 ${h.secure_form(h.route_path('logout'), request=request)}
365 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
365 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
366 ${h.end_form()}
366 ${h.end_form()}
367 </li>
367 </li>
368 </ol>
368 </ol>
369 </div>
369 </div>
370 %endif
370 %endif
371 </div>
371 </div>
372 </div>
372 </div>
373 %if c.rhodecode_user.username != h.DEFAULT_USER:
373 %if c.rhodecode_user.username != h.DEFAULT_USER:
374 <div class="pill_container">
374 <div class="pill_container">
375 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
375 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
376 </div>
376 </div>
377 % endif
377 % endif
378 </li>
378 </li>
379 </%def>
379 </%def>
380
380
381 <%def name="menu_items(active=None)">
381 <%def name="menu_items(active=None)">
382 <%
382 <%
383 def is_active(selected):
383 def is_active(selected):
384 if selected == active:
384 if selected == active:
385 return "active"
385 return "active"
386 return ""
386 return ""
387 %>
387 %>
388 <ul id="quick" class="main_nav navigation horizontal-list">
388 <ul id="quick" class="main_nav navigation horizontal-list">
389
389
390 ## Main filter
390 ## Main filter
391 <li>
391 <li>
392 <div class="menulabel main_filter_box">
392 <div class="menulabel main_filter_box">
393 <div class="main_filter_input_box">
393 <div class="main_filter_input_box">
394 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
394 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
395 </div>
395 </div>
396 <div class="main_filter_help_box">
396 <div class="main_filter_help_box">
397 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
397 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
398 </div>
398 </div>
399 </div>
399 </div>
400
400
401 <div id="main_filter_help" style="display: none">
401 <div id="main_filter_help" style="display: none">
402 Use '/' key to quickly access this field.
402 Use '/' key to quickly access this field.
403 Enter name of repository, or repository group for quick search.
403 Enter name of repository, or repository group for quick search.
404
404
405 Prefix query to allow special search:
405 Prefix query to allow special search:
406
406
407 user:admin, to search for usernames
407 user:admin, to search for usernames
408
408
409 user_group:devops, to search for user groups
409 user_group:devops, to search for user groups
410
410
411 commit:efced4, to search for commits
411 commit:efced4, to search for commits
412
412
413 </div>
413 </div>
414 </li>
414 </li>
415
415
416 ## ROOT MENU
416 ## ROOT MENU
417 %if c.rhodecode_user.username != h.DEFAULT_USER:
417 %if c.rhodecode_user.username != h.DEFAULT_USER:
418 <li class="${is_active('journal')}">
418 <li class="${is_active('journal')}">
419 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
419 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
420 <div class="menulabel">${_('Journal')}</div>
420 <div class="menulabel">${_('Journal')}</div>
421 </a>
421 </a>
422 </li>
422 </li>
423 %else:
423 %else:
424 <li class="${is_active('journal')}">
424 <li class="${is_active('journal')}">
425 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
425 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
426 <div class="menulabel">${_('Public journal')}</div>
426 <div class="menulabel">${_('Public journal')}</div>
427 </a>
427 </a>
428 </li>
428 </li>
429 %endif
429 %endif
430 <li class="${is_active('gists')}">
430 <li class="${is_active('gists')}">
431 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
431 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
432 <div class="menulabel">${_('Gists')}</div>
432 <div class="menulabel">${_('Gists')}</div>
433 </a>
433 </a>
434 </li>
434 </li>
435 <li class="${is_active('search')}">
435 <li class="${is_active('search')}">
436 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
436 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
437 <div class="menulabel">${_('Search')}</div>
437 <div class="menulabel">${_('Search')}</div>
438 </a>
438 </a>
439 </li>
439 </li>
440 % if h.HasPermissionAll('hg.admin')('access admin main page'):
440 % if h.HasPermissionAll('hg.admin')('access admin main page'):
441 <li class="${is_active('admin')}">
441 <li class="${is_active('admin')}">
442 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
442 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
443 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
443 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
444 </a>
444 </a>
445 ${admin_menu()}
445 ${admin_menu()}
446 </li>
446 </li>
447 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
447 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
448 <li class="${is_active('admin')}">
448 <li class="${is_active('admin')}">
449 <a class="menulink childs" title="${_('Delegated Admin settings')}">
449 <a class="menulink childs" title="${_('Delegated Admin settings')}">
450 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
450 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
451 </a>
451 </a>
452 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
452 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
453 c.rhodecode_user.repository_groups_admin,
453 c.rhodecode_user.repository_groups_admin,
454 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
454 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
455 </li>
455 </li>
456 % endif
456 % endif
457 ## render extra user menu
457 ## render extra user menu
458 ${usermenu(active=(active=='my_account'))}
458 ${usermenu(active=(active=='my_account'))}
459
459
460 % if c.debug_style:
460 % if c.debug_style:
461 <li class="${is_active('debug_style')}">
461 <li class="${is_active('debug_style')}">
462 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
462 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
463 <div class="menulabel">${_('Style')}</div>
463 <div class="menulabel">${_('Style')}</div>
464 </a>
464 </a>
465 </li>
465 </li>
466 % endif
466 % endif
467 </ul>
467 </ul>
468
468
469 <script type="text/javascript">
469 <script type="text/javascript">
470 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
470 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
471
471
472 var formatRepoResult = function(result, container, query, escapeMarkup) {
472 var formatRepoResult = function(result, container, query, escapeMarkup) {
473 return function(data, escapeMarkup) {
473 return function(data, escapeMarkup) {
474 if (!data.repo_id){
474 if (!data.repo_id){
475 return data.text; // optgroup text Repositories
475 return data.text; // optgroup text Repositories
476 }
476 }
477
477
478 var tmpl = '';
478 var tmpl = '';
479 var repoType = data['repo_type'];
479 var repoType = data['repo_type'];
480 var repoName = data['text'];
480 var repoName = data['text'];
481
481
482 if(data && data.type == 'repo'){
482 if(data && data.type == 'repo'){
483 if(repoType === 'hg'){
483 if(repoType === 'hg'){
484 tmpl += '<i class="icon-hg"></i> ';
484 tmpl += '<i class="icon-hg"></i> ';
485 }
485 }
486 else if(repoType === 'git'){
486 else if(repoType === 'git'){
487 tmpl += '<i class="icon-git"></i> ';
487 tmpl += '<i class="icon-git"></i> ';
488 }
488 }
489 else if(repoType === 'svn'){
489 else if(repoType === 'svn'){
490 tmpl += '<i class="icon-svn"></i> ';
490 tmpl += '<i class="icon-svn"></i> ';
491 }
491 }
492 if(data['private']){
492 if(data['private']){
493 tmpl += '<i class="icon-lock" ></i> ';
493 tmpl += '<i class="icon-lock" ></i> ';
494 }
494 }
495 else if(visualShowPublicIcon){
495 else if(visualShowPublicIcon){
496 tmpl += '<i class="icon-unlock-alt"></i> ';
496 tmpl += '<i class="icon-unlock-alt"></i> ';
497 }
497 }
498 }
498 }
499 tmpl += escapeMarkup(repoName);
499 tmpl += escapeMarkup(repoName);
500 return tmpl;
500 return tmpl;
501
501
502 }(result, escapeMarkup);
502 }(result, escapeMarkup);
503 };
503 };
504
504
505
505
506 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
506 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
507
507
508 if (value.split(':').length === 2) {
508 if (value.split(':').length === 2) {
509 value = value.split(':')[1]
509 value = value.split(':')[1]
510 }
510 }
511
511
512 var searchType = data['type'];
512 var searchType = data['type'];
513 var valueDisplay = data['value_display'];
513 var valueDisplay = data['value_display'];
514
514
515 var escapeRegExChars = function (value) {
515 var escapeRegExChars = function (value) {
516 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
516 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
517 };
517 };
518 var pattern = '(' + escapeRegExChars(value) + ')';
518 var pattern = '(' + escapeRegExChars(value) + ')';
519
519
520 // highlight match
520 // highlight match
521 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
521 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
522 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
522 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
523
523
524 var icon = '';
524 var icon = '';
525
525
526 if (searchType === 'search') {
526 if (searchType === 'hint') {
527 icon += '<i class="icon-folder-close"></i> ';
528 }
529 else if (searchType === 'search') {
527 icon += '<i class="icon-more"></i> ';
530 icon += '<i class="icon-more"></i> ';
528 }
531 }
529 else if (searchType === 'repo') {
532 else if (searchType === 'repo') {
530 if (data['repo_type'] === 'hg') {
533 if (data['repo_type'] === 'hg') {
531 icon += '<i class="icon-hg"></i> ';
534 icon += '<i class="icon-hg"></i> ';
532 }
535 }
533 else if (data['repo_type'] === 'git') {
536 else if (data['repo_type'] === 'git') {
534 icon += '<i class="icon-git"></i> ';
537 icon += '<i class="icon-git"></i> ';
535 }
538 }
536 else if (data['repo_type'] === 'svn') {
539 else if (data['repo_type'] === 'svn') {
537 icon += '<i class="icon-svn"></i> ';
540 icon += '<i class="icon-svn"></i> ';
538 }
541 }
539 if (data['private']) {
542 if (data['private']) {
540 icon += '<i class="icon-lock" ></i> ';
543 icon += '<i class="icon-lock" ></i> ';
541 }
544 }
542 else if (visualShowPublicIcon) {
545 else if (visualShowPublicIcon) {
543 icon += '<i class="icon-unlock-alt"></i> ';
546 icon += '<i class="icon-unlock-alt"></i> ';
544 }
547 }
545 }
548 }
546 else if (searchType === 'repo_group') {
549 else if (searchType === 'repo_group') {
547 icon += '<i class="icon-folder-close"></i> ';
550 icon += '<i class="icon-folder-close"></i> ';
548 }
551 }
549 else if (searchType === 'user_group') {
552 else if (searchType === 'user_group') {
550 icon += '<i class="icon-group"></i> ';
553 icon += '<i class="icon-group"></i> ';
551 }
554 }
552 else if (searchType === 'user') {
555 else if (searchType === 'user') {
553 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
556 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
554 }
557 }
555 else if (searchType === 'commit') {
558 else if (searchType === 'commit') {
556 icon += '<i class="icon-tag"></i>';
559 icon += '<i class="icon-tag"></i>';
557 }
560 }
558
561
559 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
562 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
560 return tmpl.format(icon, valueDisplay);
563 return tmpl.format(icon, valueDisplay);
561 };
564 };
562
565
563 var handleSelect = function(element, suggestion) {
566 var handleSelect = function(element, suggestion) {
567 if (suggestion.type === "hint") {
568 // we skip action
569 $('#main_filter').focus();
570 } else {
564 window.location = suggestion['url'];
571 window.location = suggestion['url'];
572 }
565 };
573 };
566 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
574 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
567 if (queryLowerCase.split(':').length === 2) {
575 if (queryLowerCase.split(':').length === 2) {
568 queryLowerCase = queryLowerCase.split(':')[1]
576 queryLowerCase = queryLowerCase.split(':')[1]
569 }
577 }
570 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
578 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
571 };
579 };
572
580
573 $('#main_filter').autocomplete({
581 $('#main_filter').autocomplete({
574 serviceUrl: pyroutes.url('goto_switcher_data'),
582 serviceUrl: pyroutes.url('goto_switcher_data'),
583 params: {"repo_group_id": templateContext.repo_group_id},
575 minChars:2,
584 minChars:2,
576 maxHeight:400,
585 maxHeight:400,
577 deferRequestBy: 300, //miliseconds
586 deferRequestBy: 300, //miliseconds
578 tabDisabled: true,
587 tabDisabled: true,
579 autoSelectFirst: true,
588 autoSelectFirst: true,
580 formatResult: autocompleteMainFilterFormatResult,
589 formatResult: autocompleteMainFilterFormatResult,
581 lookupFilter: autocompleteMainFilterResult,
590 lookupFilter: autocompleteMainFilterResult,
582 onSelect: function(element, suggestion){
591 onSelect: function(element, suggestion){
583 handleSelect(element, suggestion);
592 handleSelect(element, suggestion);
584 return false;
593 return false;
585 }
594 }
586 });
595 });
587
596
588 showMainFilterBox = function () {
597 showMainFilterBox = function () {
589 $('#main_filter_help').toggle();
598 $('#main_filter_help').toggle();
590 }
599 }
591
600
592 </script>
601 </script>
593 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
602 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
594 </%def>
603 </%def>
595
604
596 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
605 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
597 <div class="modal-dialog">
606 <div class="modal-dialog">
598 <div class="modal-content">
607 <div class="modal-content">
599 <div class="modal-header">
608 <div class="modal-header">
600 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
609 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
601 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
610 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
602 </div>
611 </div>
603 <div class="modal-body">
612 <div class="modal-body">
604 <div class="block-left">
613 <div class="block-left">
605 <table class="keyboard-mappings">
614 <table class="keyboard-mappings">
606 <tbody>
615 <tbody>
607 <tr>
616 <tr>
608 <th></th>
617 <th></th>
609 <th>${_('Site-wide shortcuts')}</th>
618 <th>${_('Site-wide shortcuts')}</th>
610 </tr>
619 </tr>
611 <%
620 <%
612 elems = [
621 elems = [
613 ('/', 'Use quick search box'),
622 ('/', 'Use quick search box'),
614 ('g h', 'Goto home page'),
623 ('g h', 'Goto home page'),
615 ('g g', 'Goto my private gists page'),
624 ('g g', 'Goto my private gists page'),
616 ('g G', 'Goto my public gists page'),
625 ('g G', 'Goto my public gists page'),
617 ('n r', 'New repository page'),
626 ('n r', 'New repository page'),
618 ('n g', 'New gist page'),
627 ('n g', 'New gist page'),
619 ]
628 ]
620 %>
629 %>
621 %for key, desc in elems:
630 %for key, desc in elems:
622 <tr>
631 <tr>
623 <td class="keys">
632 <td class="keys">
624 <span class="key tag">${key}</span>
633 <span class="key tag">${key}</span>
625 </td>
634 </td>
626 <td>${desc}</td>
635 <td>${desc}</td>
627 </tr>
636 </tr>
628 %endfor
637 %endfor
629 </tbody>
638 </tbody>
630 </table>
639 </table>
631 </div>
640 </div>
632 <div class="block-left">
641 <div class="block-left">
633 <table class="keyboard-mappings">
642 <table class="keyboard-mappings">
634 <tbody>
643 <tbody>
635 <tr>
644 <tr>
636 <th></th>
645 <th></th>
637 <th>${_('Repositories')}</th>
646 <th>${_('Repositories')}</th>
638 </tr>
647 </tr>
639 <%
648 <%
640 elems = [
649 elems = [
641 ('g s', 'Goto summary page'),
650 ('g s', 'Goto summary page'),
642 ('g c', 'Goto changelog page'),
651 ('g c', 'Goto changelog page'),
643 ('g f', 'Goto files page'),
652 ('g f', 'Goto files page'),
644 ('g F', 'Goto files page with file search activated'),
653 ('g F', 'Goto files page with file search activated'),
645 ('g p', 'Goto pull requests page'),
654 ('g p', 'Goto pull requests page'),
646 ('g o', 'Goto repository settings'),
655 ('g o', 'Goto repository settings'),
647 ('g O', 'Goto repository permissions settings'),
656 ('g O', 'Goto repository permissions settings'),
648 ]
657 ]
649 %>
658 %>
650 %for key, desc in elems:
659 %for key, desc in elems:
651 <tr>
660 <tr>
652 <td class="keys">
661 <td class="keys">
653 <span class="key tag">${key}</span>
662 <span class="key tag">${key}</span>
654 </td>
663 </td>
655 <td>${desc}</td>
664 <td>${desc}</td>
656 </tr>
665 </tr>
657 %endfor
666 %endfor
658 </tbody>
667 </tbody>
659 </table>
668 </table>
660 </div>
669 </div>
661 </div>
670 </div>
662 <div class="modal-footer">
671 <div class="modal-footer">
663 </div>
672 </div>
664 </div><!-- /.modal-content -->
673 </div><!-- /.modal-content -->
665 </div><!-- /.modal-dialog -->
674 </div><!-- /.modal-dialog -->
666 </div><!-- /.modal -->
675 </div><!-- /.modal -->
667
676
@@ -1,185 +1,188 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3
3
4 <%
4 <%
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
6 go_import_header = ''
6 go_import_header = ''
7 if hasattr(c, 'rhodecode_db_repo'):
7 if hasattr(c, 'rhodecode_db_repo'):
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10
10
11 if getattr(c, 'repo_group', None):
12 c.template_context['repo_group_id'] = c.repo_group.group_id
13
11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
14 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
15 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
16 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
17 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
15 c.template_context['rhodecode_user']['first_name'] = c.rhodecode_user.first_name
18 c.template_context['rhodecode_user']['first_name'] = c.rhodecode_user.first_name
16 c.template_context['rhodecode_user']['last_name'] = c.rhodecode_user.last_name
19 c.template_context['rhodecode_user']['last_name'] = c.rhodecode_user.last_name
17
20
18 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
21 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
19 c.template_context['default_user'] = {
22 c.template_context['default_user'] = {
20 'username': h.DEFAULT_USER,
23 'username': h.DEFAULT_USER,
21 'user_id': 1
24 'user_id': 1
22 }
25 }
23
26
24 %>
27 %>
25 <html xmlns="http://www.w3.org/1999/xhtml">
28 <html xmlns="http://www.w3.org/1999/xhtml">
26 <head>
29 <head>
27 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}"></script>
30 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}"></script>
28 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
31 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
29 <title>${self.title()}</title>
32 <title>${self.title()}</title>
30 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
33 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
31
34
32 ${h.go_import_header(request, getattr(c, 'rhodecode_db_repo', None))}
35 ${h.go_import_header(request, getattr(c, 'rhodecode_db_repo', None))}
33
36
34 % if 'safari' in (request.user_agent or '').lower():
37 % if 'safari' in (request.user_agent or '').lower():
35 <meta name="referrer" content="origin">
38 <meta name="referrer" content="origin">
36 % else:
39 % else:
37 <meta name="referrer" content="origin-when-cross-origin">
40 <meta name="referrer" content="origin-when-cross-origin">
38 % endif
41 % endif
39
42
40 <%def name="robots()">
43 <%def name="robots()">
41 <meta name="robots" content="index, nofollow"/>
44 <meta name="robots" content="index, nofollow"/>
42 </%def>
45 </%def>
43 ${self.robots()}
46 ${self.robots()}
44 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
47 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
45
48
46 ## CSS definitions
49 ## CSS definitions
47 <%def name="css()">
50 <%def name="css()">
48 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
51 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
49 <!--[if lt IE 9]>
52 <!--[if lt IE 9]>
50 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
53 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
51 <![endif]-->
54 <![endif]-->
52 ## EXTRA FOR CSS
55 ## EXTRA FOR CSS
53 ${self.css_extra()}
56 ${self.css_extra()}
54 </%def>
57 </%def>
55 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
58 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
56 <%def name="css_extra()">
59 <%def name="css_extra()">
57 </%def>
60 </%def>
58
61
59 ${self.css()}
62 ${self.css()}
60
63
61 ## JAVASCRIPT
64 ## JAVASCRIPT
62 <%def name="js()">
65 <%def name="js()">
63 <script>
66 <script>
64 // setup Polymer options
67 // setup Polymer options
65 window.Polymer = {lazyRegister: true, dom: 'shadow'};
68 window.Polymer = {lazyRegister: true, dom: 'shadow'};
66
69
67 // Load webcomponentsjs polyfill if browser does not support native Web Components
70 // Load webcomponentsjs polyfill if browser does not support native Web Components
68 (function() {
71 (function() {
69 'use strict';
72 'use strict';
70 var onload = function() {
73 var onload = function() {
71 // For native Imports, manually fire WebComponentsReady so user code
74 // For native Imports, manually fire WebComponentsReady so user code
72 // can use the same code path for native and polyfill'd imports.
75 // can use the same code path for native and polyfill'd imports.
73 if (!window.HTMLImports) {
76 if (!window.HTMLImports) {
74 document.dispatchEvent(
77 document.dispatchEvent(
75 new CustomEvent('WebComponentsReady', {bubbles: true})
78 new CustomEvent('WebComponentsReady', {bubbles: true})
76 );
79 );
77 }
80 }
78 };
81 };
79 var webComponentsSupported = (
82 var webComponentsSupported = (
80 'registerElement' in document
83 'registerElement' in document
81 && 'import' in document.createElement('link')
84 && 'import' in document.createElement('link')
82 && 'content' in document.createElement('template')
85 && 'content' in document.createElement('template')
83 );
86 );
84 if (!webComponentsSupported) {
87 if (!webComponentsSupported) {
85 } else {
88 } else {
86 onload();
89 onload();
87 }
90 }
88 })();
91 })();
89 </script>
92 </script>
90
93
91 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
94 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
92 <script type="text/javascript">
95 <script type="text/javascript">
93 // register templateContext to pass template variables to JS
96 // register templateContext to pass template variables to JS
94 var templateContext = ${h.json.dumps(c.template_context)|n};
97 var templateContext = ${h.json.dumps(c.template_context)|n};
95
98
96 var APPLICATION_URL = "${h.route_path('home').rstrip('/')}";
99 var APPLICATION_URL = "${h.route_path('home').rstrip('/')}";
97 var ASSET_URL = "${h.asset('')}";
100 var ASSET_URL = "${h.asset('')}";
98 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
101 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
99 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
102 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
100
103
101 var APPENLIGHT = {
104 var APPENLIGHT = {
102 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
105 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
103 key: '${getattr(c, "appenlight_api_public_key", "")}',
106 key: '${getattr(c, "appenlight_api_public_key", "")}',
104 % if getattr(c, 'appenlight_server_url', None):
107 % if getattr(c, 'appenlight_server_url', None):
105 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
108 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
106 % endif
109 % endif
107 requestInfo: {
110 requestInfo: {
108 % if getattr(c, 'rhodecode_user', None):
111 % if getattr(c, 'rhodecode_user', None):
109 ip: '${c.rhodecode_user.ip_addr}',
112 ip: '${c.rhodecode_user.ip_addr}',
110 username: '${c.rhodecode_user.username}'
113 username: '${c.rhodecode_user.username}'
111 % endif
114 % endif
112 },
115 },
113 tags: {
116 tags: {
114 rhodecode_version: '${c.rhodecode_version}',
117 rhodecode_version: '${c.rhodecode_version}',
115 rhodecode_edition: '${c.rhodecode_edition}'
118 rhodecode_edition: '${c.rhodecode_edition}'
116 }
119 }
117 };
120 };
118
121
119 </script>
122 </script>
120 <%include file="/base/plugins_base.mako"/>
123 <%include file="/base/plugins_base.mako"/>
121 <!--[if lt IE 9]>
124 <!--[if lt IE 9]>
122 <script language="javascript" type="text/javascript" src="${h.asset('js/src/excanvas.min.js')}"></script>
125 <script language="javascript" type="text/javascript" src="${h.asset('js/src/excanvas.min.js')}"></script>
123 <![endif]-->
126 <![endif]-->
124 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
127 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
125 <script> var alertMessagePayloads = ${h.flash.json_alerts(request=request)|n}; </script>
128 <script> var alertMessagePayloads = ${h.flash.json_alerts(request=request)|n}; </script>
126 ## avoide escaping the %N
129 ## avoide escaping the %N
127 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}"></script>
130 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}"></script>
128 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
131 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
129
132
130
133
131 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
134 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
132 ${self.js_extra()}
135 ${self.js_extra()}
133
136
134 <script type="text/javascript">
137 <script type="text/javascript">
135 Rhodecode = (function() {
138 Rhodecode = (function() {
136 function _Rhodecode() {
139 function _Rhodecode() {
137 this.comments = new CommentsController();
140 this.comments = new CommentsController();
138 }
141 }
139 return new _Rhodecode();
142 return new _Rhodecode();
140 })();
143 })();
141
144
142 $(document).ready(function(){
145 $(document).ready(function(){
143 show_more_event();
146 show_more_event();
144 timeagoActivate();
147 timeagoActivate();
145 clipboardActivate();
148 clipboardActivate();
146 })
149 })
147 </script>
150 </script>
148
151
149 </%def>
152 </%def>
150
153
151 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
154 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
152 <%def name="js_extra()"></%def>
155 <%def name="js_extra()"></%def>
153 ${self.js()}
156 ${self.js()}
154
157
155 <%def name="head_extra()"></%def>
158 <%def name="head_extra()"></%def>
156 ${self.head_extra()}
159 ${self.head_extra()}
157 ## extra stuff
160 ## extra stuff
158 %if c.pre_code:
161 %if c.pre_code:
159 ${c.pre_code|n}
162 ${c.pre_code|n}
160 %endif
163 %endif
161 </head>
164 </head>
162 <body id="body">
165 <body id="body">
163 <noscript>
166 <noscript>
164 <div class="noscript-error">
167 <div class="noscript-error">
165 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
168 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
166 </div>
169 </div>
167 </noscript>
170 </noscript>
168 ## IE hacks
171 ## IE hacks
169 <!--[if IE 7]>
172 <!--[if IE 7]>
170 <script>$(document.body).addClass('ie7')</script>
173 <script>$(document.body).addClass('ie7')</script>
171 <![endif]-->
174 <![endif]-->
172 <!--[if IE 8]>
175 <!--[if IE 8]>
173 <script>$(document.body).addClass('ie8')</script>
176 <script>$(document.body).addClass('ie8')</script>
174 <![endif]-->
177 <![endif]-->
175 <!--[if IE 9]>
178 <!--[if IE 9]>
176 <script>$(document.body).addClass('ie9')</script>
179 <script>$(document.body).addClass('ie9')</script>
177 <![endif]-->
180 <![endif]-->
178
181
179 ${next.body()}
182 ${next.body()}
180 %if c.post_code:
183 %if c.post_code:
181 ${c.post_code|n}
184 ${c.post_code|n}
182 %endif
185 %endif
183 <rhodecode-app></rhodecode-app>
186 <rhodecode-app></rhodecode-app>
184 </body>
187 </body>
185 </html>
188 </html>
General Comments 0
You need to be logged in to leave comments. Login now