##// END OF EJS Templates
ui: use more distinctive icons for search hints
marcink -
r4096:cb3daaa5 default
parent child Browse files
Show More
@@ -1,785 +1,791 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 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, CSRFRequired)
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.lib.codeblocks import filenode_as_lines_tokens
31 from rhodecode.lib.codeblocks import filenode_as_lines_tokens
32 from rhodecode.lib.index import searcher_from_config
32 from rhodecode.lib.index import searcher_from_config
33 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
33 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
34 from rhodecode.lib.ext_json import json
34 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.vcs.nodes import FileNode
35 from rhodecode.lib.vcs.nodes import FileNode
36 from rhodecode.model.db import (
36 from rhodecode.model.db import (
37 func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
37 func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo_group import RepoGroupModel
39 from rhodecode.model.repo_group import RepoGroupModel
40 from rhodecode.model.scm import RepoGroupList, RepoList
40 from rhodecode.model.scm import RepoGroupList, RepoList
41 from rhodecode.model.user import UserModel
41 from rhodecode.model.user import UserModel
42 from rhodecode.model.user_group import UserGroupModel
42 from rhodecode.model.user_group import UserGroupModel
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class HomeView(BaseAppView):
47 class HomeView(BaseAppView):
48
48
49 def load_default_context(self):
49 def load_default_context(self):
50 c = self._get_local_tmpl_context()
50 c = self._get_local_tmpl_context()
51 c.user = c.auth_user.get_instance()
51 c.user = c.auth_user.get_instance()
52
52
53 return c
53 return c
54
54
55 @LoginRequired()
55 @LoginRequired()
56 @view_config(
56 @view_config(
57 route_name='user_autocomplete_data', request_method='GET',
57 route_name='user_autocomplete_data', request_method='GET',
58 renderer='json_ext', xhr=True)
58 renderer='json_ext', xhr=True)
59 def user_autocomplete_data(self):
59 def user_autocomplete_data(self):
60 self.load_default_context()
60 self.load_default_context()
61 query = self.request.GET.get('query')
61 query = self.request.GET.get('query')
62 active = str2bool(self.request.GET.get('active') or True)
62 active = str2bool(self.request.GET.get('active') or True)
63 include_groups = str2bool(self.request.GET.get('user_groups'))
63 include_groups = str2bool(self.request.GET.get('user_groups'))
64 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
64 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
65 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
65 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
66
66
67 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
67 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
68 query, active, include_groups)
68 query, active, include_groups)
69
69
70 _users = UserModel().get_users(
70 _users = UserModel().get_users(
71 name_contains=query, only_active=active)
71 name_contains=query, only_active=active)
72
72
73 def maybe_skip_default_user(usr):
73 def maybe_skip_default_user(usr):
74 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
74 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
75 return False
75 return False
76 return True
76 return True
77 _users = filter(maybe_skip_default_user, _users)
77 _users = filter(maybe_skip_default_user, _users)
78
78
79 if include_groups:
79 if include_groups:
80 # extend with user groups
80 # extend with user groups
81 _user_groups = UserGroupModel().get_user_groups(
81 _user_groups = UserGroupModel().get_user_groups(
82 name_contains=query, only_active=active,
82 name_contains=query, only_active=active,
83 expand_groups=expand_groups)
83 expand_groups=expand_groups)
84 _users = _users + _user_groups
84 _users = _users + _user_groups
85
85
86 return {'suggestions': _users}
86 return {'suggestions': _users}
87
87
88 @LoginRequired()
88 @LoginRequired()
89 @NotAnonymous()
89 @NotAnonymous()
90 @view_config(
90 @view_config(
91 route_name='user_group_autocomplete_data', request_method='GET',
91 route_name='user_group_autocomplete_data', request_method='GET',
92 renderer='json_ext', xhr=True)
92 renderer='json_ext', xhr=True)
93 def user_group_autocomplete_data(self):
93 def user_group_autocomplete_data(self):
94 self.load_default_context()
94 self.load_default_context()
95 query = self.request.GET.get('query')
95 query = self.request.GET.get('query')
96 active = str2bool(self.request.GET.get('active') or True)
96 active = str2bool(self.request.GET.get('active') or True)
97 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
97 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
98
98
99 log.debug('generating user group list, query:%s, active:%s',
99 log.debug('generating user group list, query:%s, active:%s',
100 query, active)
100 query, active)
101
101
102 _user_groups = UserGroupModel().get_user_groups(
102 _user_groups = UserGroupModel().get_user_groups(
103 name_contains=query, only_active=active,
103 name_contains=query, only_active=active,
104 expand_groups=expand_groups)
104 expand_groups=expand_groups)
105 _user_groups = _user_groups
105 _user_groups = _user_groups
106
106
107 return {'suggestions': _user_groups}
107 return {'suggestions': _user_groups}
108
108
109 def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
109 def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
110 org_query = name_contains
110 org_query = name_contains
111 allowed_ids = self._rhodecode_user.repo_acl_ids(
111 allowed_ids = self._rhodecode_user.repo_acl_ids(
112 ['repository.read', 'repository.write', 'repository.admin'],
112 ['repository.read', 'repository.write', 'repository.admin'],
113 cache=False, name_filter=name_contains) or [-1]
113 cache=False, name_filter=name_contains) or [-1]
114
114
115 query = Repository.query()\
115 query = Repository.query()\
116 .filter(Repository.archived.isnot(true()))\
116 .filter(Repository.archived.isnot(true()))\
117 .filter(or_(
117 .filter(or_(
118 # generate multiple IN to fix limitation problems
118 # generate multiple IN to fix limitation problems
119 *in_filter_generator(Repository.repo_id, allowed_ids)
119 *in_filter_generator(Repository.repo_id, allowed_ids)
120 ))
120 ))
121
121
122 query = query.order_by(case(
122 query = query.order_by(case(
123 [
123 [
124 (Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
124 (Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
125 ],
125 ],
126 ))
126 ))
127 query = query.order_by(func.length(Repository.repo_name))
127 query = query.order_by(func.length(Repository.repo_name))
128 query = query.order_by(Repository.repo_name)
128 query = query.order_by(Repository.repo_name)
129
129
130 if repo_type:
130 if repo_type:
131 query = query.filter(Repository.repo_type == repo_type)
131 query = query.filter(Repository.repo_type == repo_type)
132
132
133 if name_contains:
133 if name_contains:
134 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
134 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
135 query = query.filter(
135 query = query.filter(
136 Repository.repo_name.ilike(ilike_expression))
136 Repository.repo_name.ilike(ilike_expression))
137 query = query.limit(limit)
137 query = query.limit(limit)
138
138
139 acl_iter = query
139 acl_iter = query
140
140
141 return [
141 return [
142 {
142 {
143 'id': obj.repo_name,
143 'id': obj.repo_name,
144 'value': org_query,
144 'value': org_query,
145 'value_display': obj.repo_name,
145 'value_display': obj.repo_name,
146 'text': obj.repo_name,
146 'text': obj.repo_name,
147 'type': 'repo',
147 'type': 'repo',
148 'repo_id': obj.repo_id,
148 'repo_id': obj.repo_id,
149 'repo_type': obj.repo_type,
149 'repo_type': obj.repo_type,
150 'private': obj.private,
150 'private': obj.private,
151 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
151 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
152 }
152 }
153 for obj in acl_iter]
153 for obj in acl_iter]
154
154
155 def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
155 def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
156 org_query = name_contains
156 org_query = name_contains
157 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
157 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
158 ['group.read', 'group.write', 'group.admin'],
158 ['group.read', 'group.write', 'group.admin'],
159 cache=False, name_filter=name_contains) or [-1]
159 cache=False, name_filter=name_contains) or [-1]
160
160
161 query = RepoGroup.query()\
161 query = RepoGroup.query()\
162 .filter(or_(
162 .filter(or_(
163 # generate multiple IN to fix limitation problems
163 # generate multiple IN to fix limitation problems
164 *in_filter_generator(RepoGroup.group_id, allowed_ids)
164 *in_filter_generator(RepoGroup.group_id, allowed_ids)
165 ))
165 ))
166
166
167 query = query.order_by(case(
167 query = query.order_by(case(
168 [
168 [
169 (RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
169 (RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
170 ],
170 ],
171 ))
171 ))
172 query = query.order_by(func.length(RepoGroup.group_name))
172 query = query.order_by(func.length(RepoGroup.group_name))
173 query = query.order_by(RepoGroup.group_name)
173 query = query.order_by(RepoGroup.group_name)
174
174
175 if name_contains:
175 if name_contains:
176 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
176 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
177 query = query.filter(
177 query = query.filter(
178 RepoGroup.group_name.ilike(ilike_expression))
178 RepoGroup.group_name.ilike(ilike_expression))
179 query = query.limit(limit)
179 query = query.limit(limit)
180
180
181 acl_iter = query
181 acl_iter = query
182
182
183 return [
183 return [
184 {
184 {
185 'id': obj.group_name,
185 'id': obj.group_name,
186 'value': org_query,
186 'value': org_query,
187 'value_display': obj.group_name,
187 'value_display': obj.group_name,
188 'text': obj.group_name,
188 'text': obj.group_name,
189 'type': 'repo_group',
189 'type': 'repo_group',
190 'repo_group_id': obj.group_id,
190 'repo_group_id': obj.group_id,
191 'url': h.route_path(
191 'url': h.route_path(
192 'repo_group_home', repo_group_name=obj.group_name)
192 'repo_group_home', repo_group_name=obj.group_name)
193 }
193 }
194 for obj in acl_iter]
194 for obj in acl_iter]
195
195
196 def _get_user_list(self, name_contains=None, limit=20):
196 def _get_user_list(self, name_contains=None, limit=20):
197 org_query = name_contains
197 org_query = name_contains
198 if not name_contains:
198 if not name_contains:
199 return [], False
199 return [], False
200
200
201 # TODO(marcink): should all logged in users be allowed to search others?
201 # TODO(marcink): should all logged in users be allowed to search others?
202 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
202 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
203 if not allowed_user_search:
203 if not allowed_user_search:
204 return [], False
204 return [], False
205
205
206 name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
206 name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
207 if len(name_contains) != 1:
207 if len(name_contains) != 1:
208 return [], False
208 return [], False
209
209
210 name_contains = name_contains[0]
210 name_contains = name_contains[0]
211
211
212 query = User.query()\
212 query = User.query()\
213 .order_by(func.length(User.username))\
213 .order_by(func.length(User.username))\
214 .order_by(User.username) \
214 .order_by(User.username) \
215 .filter(User.username != User.DEFAULT_USER)
215 .filter(User.username != User.DEFAULT_USER)
216
216
217 if name_contains:
217 if name_contains:
218 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
218 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
219 query = query.filter(
219 query = query.filter(
220 User.username.ilike(ilike_expression))
220 User.username.ilike(ilike_expression))
221 query = query.limit(limit)
221 query = query.limit(limit)
222
222
223 acl_iter = query
223 acl_iter = query
224
224
225 return [
225 return [
226 {
226 {
227 'id': obj.user_id,
227 'id': obj.user_id,
228 'value': org_query,
228 'value': org_query,
229 'value_display': 'user: `{}`'.format(obj.username),
229 'value_display': 'user: `{}`'.format(obj.username),
230 'type': 'user',
230 'type': 'user',
231 'icon_link': h.gravatar_url(obj.email, 30),
231 'icon_link': h.gravatar_url(obj.email, 30),
232 'url': h.route_path(
232 'url': h.route_path(
233 'user_profile', username=obj.username)
233 'user_profile', username=obj.username)
234 }
234 }
235 for obj in acl_iter], True
235 for obj in acl_iter], True
236
236
237 def _get_user_groups_list(self, name_contains=None, limit=20):
237 def _get_user_groups_list(self, name_contains=None, limit=20):
238 org_query = name_contains
238 org_query = name_contains
239 if not name_contains:
239 if not name_contains:
240 return [], False
240 return [], False
241
241
242 # TODO(marcink): should all logged in users be allowed to search others?
242 # TODO(marcink): should all logged in users be allowed to search others?
243 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
243 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
244 if not allowed_user_search:
244 if not allowed_user_search:
245 return [], False
245 return [], False
246
246
247 name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
247 name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
248 if len(name_contains) != 1:
248 if len(name_contains) != 1:
249 return [], False
249 return [], False
250
250
251 name_contains = name_contains[0]
251 name_contains = name_contains[0]
252
252
253 query = UserGroup.query()\
253 query = UserGroup.query()\
254 .order_by(func.length(UserGroup.users_group_name))\
254 .order_by(func.length(UserGroup.users_group_name))\
255 .order_by(UserGroup.users_group_name)
255 .order_by(UserGroup.users_group_name)
256
256
257 if name_contains:
257 if name_contains:
258 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
258 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
259 query = query.filter(
259 query = query.filter(
260 UserGroup.users_group_name.ilike(ilike_expression))
260 UserGroup.users_group_name.ilike(ilike_expression))
261 query = query.limit(limit)
261 query = query.limit(limit)
262
262
263 acl_iter = query
263 acl_iter = query
264
264
265 return [
265 return [
266 {
266 {
267 'id': obj.users_group_id,
267 'id': obj.users_group_id,
268 'value': org_query,
268 'value': org_query,
269 'value_display': 'user_group: `{}`'.format(obj.users_group_name),
269 'value_display': 'user_group: `{}`'.format(obj.users_group_name),
270 'type': 'user_group',
270 'type': 'user_group',
271 'url': h.route_path(
271 'url': h.route_path(
272 'user_group_profile', user_group_name=obj.users_group_name)
272 'user_group_profile', user_group_name=obj.users_group_name)
273 }
273 }
274 for obj in acl_iter], True
274 for obj in acl_iter], True
275
275
276 def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
276 def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
277 repo_name = repo_group_name = None
277 repo_name = repo_group_name = None
278 if repo:
278 if repo:
279 repo_name = repo.repo_name
279 repo_name = repo.repo_name
280 if repo_group:
280 if repo_group:
281 repo_group_name = repo_group.group_name
281 repo_group_name = repo_group.group_name
282
282
283 org_query = query
283 org_query = query
284 if not query or len(query) < 3 or not searcher:
284 if not query or len(query) < 3 or not searcher:
285 return [], False
285 return [], False
286
286
287 commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
287 commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
288
288
289 if len(commit_hashes) != 1:
289 if len(commit_hashes) != 1:
290 return [], False
290 return [], False
291
291
292 commit_hash = commit_hashes[0]
292 commit_hash = commit_hashes[0]
293
293
294 result = searcher.search(
294 result = searcher.search(
295 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
295 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
296 repo_name, repo_group_name, raise_on_exc=False)
296 repo_name, repo_group_name, raise_on_exc=False)
297
297
298 commits = []
298 commits = []
299 for entry in result['results']:
299 for entry in result['results']:
300 repo_data = {
300 repo_data = {
301 'repository_id': entry.get('repository_id'),
301 'repository_id': entry.get('repository_id'),
302 'repository_type': entry.get('repo_type'),
302 'repository_type': entry.get('repo_type'),
303 'repository_name': entry.get('repository'),
303 'repository_name': entry.get('repository'),
304 }
304 }
305
305
306 commit_entry = {
306 commit_entry = {
307 'id': entry['commit_id'],
307 'id': entry['commit_id'],
308 'value': org_query,
308 'value': org_query,
309 'value_display': '`{}` commit: {}'.format(
309 'value_display': '`{}` commit: {}'.format(
310 entry['repository'], entry['commit_id']),
310 entry['repository'], entry['commit_id']),
311 'type': 'commit',
311 'type': 'commit',
312 'repo': entry['repository'],
312 'repo': entry['repository'],
313 'repo_data': repo_data,
313 'repo_data': repo_data,
314
314
315 'url': h.route_path(
315 'url': h.route_path(
316 'repo_commit',
316 'repo_commit',
317 repo_name=entry['repository'], commit_id=entry['commit_id'])
317 repo_name=entry['repository'], commit_id=entry['commit_id'])
318 }
318 }
319
319
320 commits.append(commit_entry)
320 commits.append(commit_entry)
321 return commits, True
321 return commits, True
322
322
323 def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
323 def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
324 repo_name = repo_group_name = None
324 repo_name = repo_group_name = None
325 if repo:
325 if repo:
326 repo_name = repo.repo_name
326 repo_name = repo.repo_name
327 if repo_group:
327 if repo_group:
328 repo_group_name = repo_group.group_name
328 repo_group_name = repo_group.group_name
329
329
330 org_query = query
330 org_query = query
331 if not query or len(query) < 3 or not searcher:
331 if not query or len(query) < 3 or not searcher:
332 return [], False
332 return [], False
333
333
334 paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
334 paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
335 if len(paths_re) != 1:
335 if len(paths_re) != 1:
336 return [], False
336 return [], False
337
337
338 file_path = paths_re[0]
338 file_path = paths_re[0]
339
339
340 search_path = searcher.escape_specials(file_path)
340 search_path = searcher.escape_specials(file_path)
341 result = searcher.search(
341 result = searcher.search(
342 'file.raw:*{}*'.format(search_path), 'path', auth_user,
342 'file.raw:*{}*'.format(search_path), 'path', auth_user,
343 repo_name, repo_group_name, raise_on_exc=False)
343 repo_name, repo_group_name, raise_on_exc=False)
344
344
345 files = []
345 files = []
346 for entry in result['results']:
346 for entry in result['results']:
347 repo_data = {
347 repo_data = {
348 'repository_id': entry.get('repository_id'),
348 'repository_id': entry.get('repository_id'),
349 'repository_type': entry.get('repo_type'),
349 'repository_type': entry.get('repo_type'),
350 'repository_name': entry.get('repository'),
350 'repository_name': entry.get('repository'),
351 }
351 }
352
352
353 file_entry = {
353 file_entry = {
354 'id': entry['commit_id'],
354 'id': entry['commit_id'],
355 'value': org_query,
355 'value': org_query,
356 'value_display': '`{}` file: {}'.format(
356 'value_display': '`{}` file: {}'.format(
357 entry['repository'], entry['file']),
357 entry['repository'], entry['file']),
358 'type': 'file',
358 'type': 'file',
359 'repo': entry['repository'],
359 'repo': entry['repository'],
360 'repo_data': repo_data,
360 'repo_data': repo_data,
361
361
362 'url': h.route_path(
362 'url': h.route_path(
363 'repo_files',
363 'repo_files',
364 repo_name=entry['repository'], commit_id=entry['commit_id'],
364 repo_name=entry['repository'], commit_id=entry['commit_id'],
365 f_path=entry['file'])
365 f_path=entry['file'])
366 }
366 }
367
367
368 files.append(file_entry)
368 files.append(file_entry)
369 return files, True
369 return files, True
370
370
371 @LoginRequired()
371 @LoginRequired()
372 @view_config(
372 @view_config(
373 route_name='repo_list_data', request_method='GET',
373 route_name='repo_list_data', request_method='GET',
374 renderer='json_ext', xhr=True)
374 renderer='json_ext', xhr=True)
375 def repo_list_data(self):
375 def repo_list_data(self):
376 _ = self.request.translate
376 _ = self.request.translate
377 self.load_default_context()
377 self.load_default_context()
378
378
379 query = self.request.GET.get('query')
379 query = self.request.GET.get('query')
380 repo_type = self.request.GET.get('repo_type')
380 repo_type = self.request.GET.get('repo_type')
381 log.debug('generating repo list, query:%s, repo_type:%s',
381 log.debug('generating repo list, query:%s, repo_type:%s',
382 query, repo_type)
382 query, repo_type)
383
383
384 res = []
384 res = []
385 repos = self._get_repo_list(query, repo_type=repo_type)
385 repos = self._get_repo_list(query, repo_type=repo_type)
386 if repos:
386 if repos:
387 res.append({
387 res.append({
388 'text': _('Repositories'),
388 'text': _('Repositories'),
389 'children': repos
389 'children': repos
390 })
390 })
391
391
392 data = {
392 data = {
393 'more': False,
393 'more': False,
394 'results': res
394 'results': res
395 }
395 }
396 return data
396 return data
397
397
398 @LoginRequired()
398 @LoginRequired()
399 @view_config(
399 @view_config(
400 route_name='repo_group_list_data', request_method='GET',
400 route_name='repo_group_list_data', request_method='GET',
401 renderer='json_ext', xhr=True)
401 renderer='json_ext', xhr=True)
402 def repo_group_list_data(self):
402 def repo_group_list_data(self):
403 _ = self.request.translate
403 _ = self.request.translate
404 self.load_default_context()
404 self.load_default_context()
405
405
406 query = self.request.GET.get('query')
406 query = self.request.GET.get('query')
407
407
408 log.debug('generating repo group list, query:%s',
408 log.debug('generating repo group list, query:%s',
409 query)
409 query)
410
410
411 res = []
411 res = []
412 repo_groups = self._get_repo_group_list(query)
412 repo_groups = self._get_repo_group_list(query)
413 if repo_groups:
413 if repo_groups:
414 res.append({
414 res.append({
415 'text': _('Repository Groups'),
415 'text': _('Repository Groups'),
416 'children': repo_groups
416 'children': repo_groups
417 })
417 })
418
418
419 data = {
419 data = {
420 'more': False,
420 'more': False,
421 'results': res
421 'results': res
422 }
422 }
423 return data
423 return data
424
424
425 def _get_default_search_queries(self, search_context, searcher, query):
425 def _get_default_search_queries(self, search_context, searcher, query):
426 if not searcher:
426 if not searcher:
427 return []
427 return []
428
428
429 is_es_6 = searcher.is_es_6
429 is_es_6 = searcher.is_es_6
430
430
431 queries = []
431 queries = []
432 repo_group_name, repo_name, repo_context = None, None, None
432 repo_group_name, repo_name, repo_context = None, None, None
433
433
434 # repo group context
434 # repo group context
435 if search_context.get('search_context[repo_group_name]'):
435 if search_context.get('search_context[repo_group_name]'):
436 repo_group_name = search_context.get('search_context[repo_group_name]')
436 repo_group_name = search_context.get('search_context[repo_group_name]')
437 if search_context.get('search_context[repo_name]'):
437 if search_context.get('search_context[repo_name]'):
438 repo_name = search_context.get('search_context[repo_name]')
438 repo_name = search_context.get('search_context[repo_name]')
439 repo_context = search_context.get('search_context[repo_view_type]')
439 repo_context = search_context.get('search_context[repo_view_type]')
440
440
441 if is_es_6 and repo_name:
441 if is_es_6 and repo_name:
442 # files
442 # files
443 def query_modifier():
443 def query_modifier():
444 qry = query
444 qry = query
445 return {'q': qry, 'type': 'content'}
445 return {'q': qry, 'type': 'content'}
446
446
447 label = u'File search for `{}`'.format(h.escape(query))
447 label = u'File search for `{}`'.format(h.escape(query))
448 file_qry = {
448 file_qry = {
449 'id': -10,
449 'id': -10,
450 'value': query,
450 'value': query,
451 'value_display': label,
451 'value_display': label,
452 'value_icon': '<i class="icon-code"></i>',
452 'type': 'search',
453 'type': 'search',
453 'subtype': 'repo',
454 'subtype': 'repo',
454 'url': h.route_path('search_repo',
455 'url': h.route_path('search_repo',
455 repo_name=repo_name,
456 repo_name=repo_name,
456 _query=query_modifier())
457 _query=query_modifier())
457 }
458 }
458
459
459 # commits
460 # commits
460 def query_modifier():
461 def query_modifier():
461 qry = query
462 qry = query
462 return {'q': qry, 'type': 'commit'}
463 return {'q': qry, 'type': 'commit'}
463
464
464 label = u'Commit search for `{}`'.format(h.escape(query))
465 label = u'Commit search for `{}`'.format(h.escape(query))
465 commit_qry = {
466 commit_qry = {
466 'id': -20,
467 'id': -20,
467 'value': query,
468 'value': query,
468 'value_display': label,
469 'value_display': label,
470 'value_icon': '<i class="icon-history"></i>',
469 'type': 'search',
471 'type': 'search',
470 'subtype': 'repo',
472 'subtype': 'repo',
471 'url': h.route_path('search_repo',
473 'url': h.route_path('search_repo',
472 repo_name=repo_name,
474 repo_name=repo_name,
473 _query=query_modifier())
475 _query=query_modifier())
474 }
476 }
475
477
476 if repo_context in ['commit', 'commits']:
478 if repo_context in ['commit', 'commits']:
477 queries.extend([commit_qry, file_qry])
479 queries.extend([commit_qry, file_qry])
478 elif repo_context in ['files', 'summary']:
480 elif repo_context in ['files', 'summary']:
479 queries.extend([file_qry, commit_qry])
481 queries.extend([file_qry, commit_qry])
480 else:
482 else:
481 queries.extend([commit_qry, file_qry])
483 queries.extend([commit_qry, file_qry])
482
484
483 elif is_es_6 and repo_group_name:
485 elif is_es_6 and repo_group_name:
484 # files
486 # files
485 def query_modifier():
487 def query_modifier():
486 qry = query
488 qry = query
487 return {'q': qry, 'type': 'content'}
489 return {'q': qry, 'type': 'content'}
488
490
489 label = u'File search for `{}`'.format(query)
491 label = u'File search for `{}`'.format(query)
490 file_qry = {
492 file_qry = {
491 'id': -30,
493 'id': -30,
492 'value': query,
494 'value': query,
493 'value_display': label,
495 'value_display': label,
496 'value_icon': '<i class="icon-code"></i>',
494 'type': 'search',
497 'type': 'search',
495 'subtype': 'repo_group',
498 'subtype': 'repo_group',
496 'url': h.route_path('search_repo_group',
499 'url': h.route_path('search_repo_group',
497 repo_group_name=repo_group_name,
500 repo_group_name=repo_group_name,
498 _query=query_modifier())
501 _query=query_modifier())
499 }
502 }
500
503
501 # commits
504 # commits
502 def query_modifier():
505 def query_modifier():
503 qry = query
506 qry = query
504 return {'q': qry, 'type': 'commit'}
507 return {'q': qry, 'type': 'commit'}
505
508
506 label = u'Commit search for `{}`'.format(query)
509 label = u'Commit search for `{}`'.format(query)
507 commit_qry = {
510 commit_qry = {
508 'id': -40,
511 'id': -40,
509 'value': query,
512 'value': query,
510 'value_display': label,
513 'value_display': label,
514 'value_icon': '<i class="icon-history"></i>',
511 'type': 'search',
515 'type': 'search',
512 'subtype': 'repo_group',
516 'subtype': 'repo_group',
513 'url': h.route_path('search_repo_group',
517 'url': h.route_path('search_repo_group',
514 repo_group_name=repo_group_name,
518 repo_group_name=repo_group_name,
515 _query=query_modifier())
519 _query=query_modifier())
516 }
520 }
517
521
518 if repo_context in ['commit', 'commits']:
522 if repo_context in ['commit', 'commits']:
519 queries.extend([commit_qry, file_qry])
523 queries.extend([commit_qry, file_qry])
520 elif repo_context in ['files', 'summary']:
524 elif repo_context in ['files', 'summary']:
521 queries.extend([file_qry, commit_qry])
525 queries.extend([file_qry, commit_qry])
522 else:
526 else:
523 queries.extend([commit_qry, file_qry])
527 queries.extend([commit_qry, file_qry])
524
528
525 # Global, not scoped
529 # Global, not scoped
526 if not queries:
530 if not queries:
527 queries.append(
531 queries.append(
528 {
532 {
529 'id': -1,
533 'id': -1,
530 'value': query,
534 'value': query,
531 'value_display': u'File search for: `{}`'.format(query),
535 'value_display': u'File search for: `{}`'.format(query),
536 'value_icon': '<i class="icon-code"></i>',
532 'type': 'search',
537 'type': 'search',
533 'subtype': 'global',
538 'subtype': 'global',
534 'url': h.route_path('search',
539 'url': h.route_path('search',
535 _query={'q': query, 'type': 'content'})
540 _query={'q': query, 'type': 'content'})
536 })
541 })
537 queries.append(
542 queries.append(
538 {
543 {
539 'id': -2,
544 'id': -2,
540 'value': query,
545 'value': query,
541 'value_display': u'Commit search for: `{}`'.format(query),
546 'value_display': u'Commit search for: `{}`'.format(query),
547 'value_icon': '<i class="icon-history"></i>',
542 'type': 'search',
548 'type': 'search',
543 'subtype': 'global',
549 'subtype': 'global',
544 'url': h.route_path('search',
550 'url': h.route_path('search',
545 _query={'q': query, 'type': 'commit'})
551 _query={'q': query, 'type': 'commit'})
546 })
552 })
547
553
548 return queries
554 return queries
549
555
550 @LoginRequired()
556 @LoginRequired()
551 @view_config(
557 @view_config(
552 route_name='goto_switcher_data', request_method='GET',
558 route_name='goto_switcher_data', request_method='GET',
553 renderer='json_ext', xhr=True)
559 renderer='json_ext', xhr=True)
554 def goto_switcher_data(self):
560 def goto_switcher_data(self):
555 c = self.load_default_context()
561 c = self.load_default_context()
556
562
557 _ = self.request.translate
563 _ = self.request.translate
558
564
559 query = self.request.GET.get('query')
565 query = self.request.GET.get('query')
560 log.debug('generating main filter data, query %s', query)
566 log.debug('generating main filter data, query %s', query)
561
567
562 res = []
568 res = []
563 if not query:
569 if not query:
564 return {'suggestions': res}
570 return {'suggestions': res}
565
571
566 def no_match(name):
572 def no_match(name):
567 return {
573 return {
568 'id': -1,
574 'id': -1,
569 'value': "",
575 'value': "",
570 'value_display': name,
576 'value_display': name,
571 'type': 'text',
577 'type': 'text',
572 'url': ""
578 'url': ""
573 }
579 }
574 searcher = searcher_from_config(self.request.registry.settings)
580 searcher = searcher_from_config(self.request.registry.settings)
575 has_specialized_search = False
581 has_specialized_search = False
576
582
577 # set repo context
583 # set repo context
578 repo = None
584 repo = None
579 repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
585 repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
580 if repo_id:
586 if repo_id:
581 repo = Repository.get(repo_id)
587 repo = Repository.get(repo_id)
582
588
583 # set group context
589 # set group context
584 repo_group = None
590 repo_group = None
585 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
591 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
586 if repo_group_id:
592 if repo_group_id:
587 repo_group = RepoGroup.get(repo_group_id)
593 repo_group = RepoGroup.get(repo_group_id)
588 prefix_match = False
594 prefix_match = False
589
595
590 # user: type search
596 # user: type search
591 if not prefix_match:
597 if not prefix_match:
592 users, prefix_match = self._get_user_list(query)
598 users, prefix_match = self._get_user_list(query)
593 if users:
599 if users:
594 has_specialized_search = True
600 has_specialized_search = True
595 for serialized_user in users:
601 for serialized_user in users:
596 res.append(serialized_user)
602 res.append(serialized_user)
597 elif prefix_match:
603 elif prefix_match:
598 has_specialized_search = True
604 has_specialized_search = True
599 res.append(no_match('No matching users found'))
605 res.append(no_match('No matching users found'))
600
606
601 # user_group: type search
607 # user_group: type search
602 if not prefix_match:
608 if not prefix_match:
603 user_groups, prefix_match = self._get_user_groups_list(query)
609 user_groups, prefix_match = self._get_user_groups_list(query)
604 if user_groups:
610 if user_groups:
605 has_specialized_search = True
611 has_specialized_search = True
606 for serialized_user_group in user_groups:
612 for serialized_user_group in user_groups:
607 res.append(serialized_user_group)
613 res.append(serialized_user_group)
608 elif prefix_match:
614 elif prefix_match:
609 has_specialized_search = True
615 has_specialized_search = True
610 res.append(no_match('No matching user groups found'))
616 res.append(no_match('No matching user groups found'))
611
617
612 # FTS commit: type search
618 # FTS commit: type search
613 if not prefix_match:
619 if not prefix_match:
614 commits, prefix_match = self._get_hash_commit_list(
620 commits, prefix_match = self._get_hash_commit_list(
615 c.auth_user, searcher, query, repo, repo_group)
621 c.auth_user, searcher, query, repo, repo_group)
616 if commits:
622 if commits:
617 has_specialized_search = True
623 has_specialized_search = True
618 unique_repos = collections.OrderedDict()
624 unique_repos = collections.OrderedDict()
619 for commit in commits:
625 for commit in commits:
620 repo_name = commit['repo']
626 repo_name = commit['repo']
621 unique_repos.setdefault(repo_name, []).append(commit)
627 unique_repos.setdefault(repo_name, []).append(commit)
622
628
623 for _repo, commits in unique_repos.items():
629 for _repo, commits in unique_repos.items():
624 for commit in commits:
630 for commit in commits:
625 res.append(commit)
631 res.append(commit)
626 elif prefix_match:
632 elif prefix_match:
627 has_specialized_search = True
633 has_specialized_search = True
628 res.append(no_match('No matching commits found'))
634 res.append(no_match('No matching commits found'))
629
635
630 # FTS file: type search
636 # FTS file: type search
631 if not prefix_match:
637 if not prefix_match:
632 paths, prefix_match = self._get_path_list(
638 paths, prefix_match = self._get_path_list(
633 c.auth_user, searcher, query, repo, repo_group)
639 c.auth_user, searcher, query, repo, repo_group)
634 if paths:
640 if paths:
635 has_specialized_search = True
641 has_specialized_search = True
636 unique_repos = collections.OrderedDict()
642 unique_repos = collections.OrderedDict()
637 for path in paths:
643 for path in paths:
638 repo_name = path['repo']
644 repo_name = path['repo']
639 unique_repos.setdefault(repo_name, []).append(path)
645 unique_repos.setdefault(repo_name, []).append(path)
640
646
641 for repo, paths in unique_repos.items():
647 for repo, paths in unique_repos.items():
642 for path in paths:
648 for path in paths:
643 res.append(path)
649 res.append(path)
644 elif prefix_match:
650 elif prefix_match:
645 has_specialized_search = True
651 has_specialized_search = True
646 res.append(no_match('No matching files found'))
652 res.append(no_match('No matching files found'))
647
653
648 # main suggestions
654 # main suggestions
649 if not has_specialized_search:
655 if not has_specialized_search:
650 repo_group_name = ''
656 repo_group_name = ''
651 if repo_group:
657 if repo_group:
652 repo_group_name = repo_group.group_name
658 repo_group_name = repo_group.group_name
653
659
654 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
660 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
655 res.append(_q)
661 res.append(_q)
656
662
657 repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
663 repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
658 for serialized_repo_group in repo_groups:
664 for serialized_repo_group in repo_groups:
659 res.append(serialized_repo_group)
665 res.append(serialized_repo_group)
660
666
661 repos = self._get_repo_list(query, repo_group_name=repo_group_name)
667 repos = self._get_repo_list(query, repo_group_name=repo_group_name)
662 for serialized_repo in repos:
668 for serialized_repo in repos:
663 res.append(serialized_repo)
669 res.append(serialized_repo)
664
670
665 if not repos and not repo_groups:
671 if not repos and not repo_groups:
666 res.append(no_match('No matches found'))
672 res.append(no_match('No matches found'))
667
673
668 return {'suggestions': res}
674 return {'suggestions': res}
669
675
670 def _get_groups_and_repos(self, repo_group_id=None):
676 def _get_groups_and_repos(self, repo_group_id=None):
671 # repo groups groups
677 # repo groups groups
672 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
678 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
673 _perms = ['group.read', 'group.write', 'group.admin']
679 _perms = ['group.read', 'group.write', 'group.admin']
674 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
680 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
675 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
681 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
676 repo_group_list=repo_group_list_acl, admin=False)
682 repo_group_list=repo_group_list_acl, admin=False)
677
683
678 # repositories
684 # repositories
679 repo_list = Repository.get_all_repos(group_id=repo_group_id)
685 repo_list = Repository.get_all_repos(group_id=repo_group_id)
680 _perms = ['repository.read', 'repository.write', 'repository.admin']
686 _perms = ['repository.read', 'repository.write', 'repository.admin']
681 repo_list_acl = RepoList(repo_list, perm_set=_perms)
687 repo_list_acl = RepoList(repo_list, perm_set=_perms)
682 repo_data = RepoModel().get_repos_as_dict(
688 repo_data = RepoModel().get_repos_as_dict(
683 repo_list=repo_list_acl, admin=False)
689 repo_list=repo_list_acl, admin=False)
684
690
685 return repo_data, repo_group_data
691 return repo_data, repo_group_data
686
692
687 @LoginRequired()
693 @LoginRequired()
688 @view_config(
694 @view_config(
689 route_name='home', request_method='GET',
695 route_name='home', request_method='GET',
690 renderer='rhodecode:templates/index.mako')
696 renderer='rhodecode:templates/index.mako')
691 def main_page(self):
697 def main_page(self):
692 c = self.load_default_context()
698 c = self.load_default_context()
693 c.repo_group = None
699 c.repo_group = None
694
700
695 repo_data, repo_group_data = self._get_groups_and_repos()
701 repo_data, repo_group_data = self._get_groups_and_repos()
696 # json used to render the grids
702 # json used to render the grids
697 c.repos_data = json.dumps(repo_data)
703 c.repos_data = json.dumps(repo_data)
698 c.repo_groups_data = json.dumps(repo_group_data)
704 c.repo_groups_data = json.dumps(repo_group_data)
699
705
700 return self._get_template_context(c)
706 return self._get_template_context(c)
701
707
702 @LoginRequired()
708 @LoginRequired()
703 @HasRepoGroupPermissionAnyDecorator(
709 @HasRepoGroupPermissionAnyDecorator(
704 'group.read', 'group.write', 'group.admin')
710 'group.read', 'group.write', 'group.admin')
705 @view_config(
711 @view_config(
706 route_name='repo_group_home', request_method='GET',
712 route_name='repo_group_home', request_method='GET',
707 renderer='rhodecode:templates/index_repo_group.mako')
713 renderer='rhodecode:templates/index_repo_group.mako')
708 @view_config(
714 @view_config(
709 route_name='repo_group_home_slash', request_method='GET',
715 route_name='repo_group_home_slash', request_method='GET',
710 renderer='rhodecode:templates/index_repo_group.mako')
716 renderer='rhodecode:templates/index_repo_group.mako')
711 def repo_group_main_page(self):
717 def repo_group_main_page(self):
712 c = self.load_default_context()
718 c = self.load_default_context()
713 c.repo_group = self.request.db_repo_group
719 c.repo_group = self.request.db_repo_group
714 repo_data, repo_group_data = self._get_groups_and_repos(c.repo_group.group_id)
720 repo_data, repo_group_data = self._get_groups_and_repos(c.repo_group.group_id)
715
721
716 # update every 5 min
722 # update every 5 min
717 if self.request.db_repo_group.last_commit_cache_update_diff > 60 * 5:
723 if self.request.db_repo_group.last_commit_cache_update_diff > 60 * 5:
718 self.request.db_repo_group.update_commit_cache()
724 self.request.db_repo_group.update_commit_cache()
719
725
720 # json used to render the grids
726 # json used to render the grids
721 c.repos_data = json.dumps(repo_data)
727 c.repos_data = json.dumps(repo_data)
722 c.repo_groups_data = json.dumps(repo_group_data)
728 c.repo_groups_data = json.dumps(repo_group_data)
723
729
724 return self._get_template_context(c)
730 return self._get_template_context(c)
725
731
726 @LoginRequired()
732 @LoginRequired()
727 @CSRFRequired()
733 @CSRFRequired()
728 @view_config(
734 @view_config(
729 route_name='markup_preview', request_method='POST',
735 route_name='markup_preview', request_method='POST',
730 renderer='string', xhr=True)
736 renderer='string', xhr=True)
731 def markup_preview(self):
737 def markup_preview(self):
732 # Technically a CSRF token is not needed as no state changes with this
738 # Technically a CSRF token is not needed as no state changes with this
733 # call. However, as this is a POST is better to have it, so automated
739 # call. However, as this is a POST is better to have it, so automated
734 # tools don't flag it as potential CSRF.
740 # tools don't flag it as potential CSRF.
735 # Post is required because the payload could be bigger than the maximum
741 # Post is required because the payload could be bigger than the maximum
736 # allowed by GET.
742 # allowed by GET.
737
743
738 text = self.request.POST.get('text')
744 text = self.request.POST.get('text')
739 renderer = self.request.POST.get('renderer') or 'rst'
745 renderer = self.request.POST.get('renderer') or 'rst'
740 if text:
746 if text:
741 return h.render(text, renderer=renderer, mentions=True)
747 return h.render(text, renderer=renderer, mentions=True)
742 return ''
748 return ''
743
749
744 @LoginRequired()
750 @LoginRequired()
745 @CSRFRequired()
751 @CSRFRequired()
746 @view_config(
752 @view_config(
747 route_name='file_preview', request_method='POST',
753 route_name='file_preview', request_method='POST',
748 renderer='string', xhr=True)
754 renderer='string', xhr=True)
749 def file_preview(self):
755 def file_preview(self):
750 # Technically a CSRF token is not needed as no state changes with this
756 # Technically a CSRF token is not needed as no state changes with this
751 # call. However, as this is a POST is better to have it, so automated
757 # call. However, as this is a POST is better to have it, so automated
752 # tools don't flag it as potential CSRF.
758 # tools don't flag it as potential CSRF.
753 # Post is required because the payload could be bigger than the maximum
759 # Post is required because the payload could be bigger than the maximum
754 # allowed by GET.
760 # allowed by GET.
755
761
756 text = self.request.POST.get('text')
762 text = self.request.POST.get('text')
757 file_path = self.request.POST.get('file_path')
763 file_path = self.request.POST.get('file_path')
758
764
759 renderer = h.renderer_from_filename(file_path)
765 renderer = h.renderer_from_filename(file_path)
760
766
761 if renderer:
767 if renderer:
762 return h.render(text, renderer=renderer, mentions=True)
768 return h.render(text, renderer=renderer, mentions=True)
763 else:
769 else:
764 self.load_default_context()
770 self.load_default_context()
765 _render = self.request.get_partial_renderer(
771 _render = self.request.get_partial_renderer(
766 'rhodecode:templates/files/file_content.mako')
772 'rhodecode:templates/files/file_content.mako')
767
773
768 lines = filenode_as_lines_tokens(FileNode(file_path, text))
774 lines = filenode_as_lines_tokens(FileNode(file_path, text))
769
775
770 return _render('render_lines', lines)
776 return _render('render_lines', lines)
771
777
772 @LoginRequired()
778 @LoginRequired()
773 @CSRFRequired()
779 @CSRFRequired()
774 @view_config(
780 @view_config(
775 route_name='store_user_session_value', request_method='POST',
781 route_name='store_user_session_value', request_method='POST',
776 renderer='string', xhr=True)
782 renderer='string', xhr=True)
777 def store_user_session_attr(self):
783 def store_user_session_attr(self):
778 key = self.request.POST.get('key')
784 key = self.request.POST.get('key')
779 val = self.request.POST.get('val')
785 val = self.request.POST.get('val')
780
786
781 existing_value = self.request.session.get(key)
787 existing_value = self.request.session.get(key)
782 if existing_value != val:
788 if existing_value != val:
783 self.request.session[key] = val
789 self.request.session[key] = val
784
790
785 return 'stored:{}:{}'.format(key, val)
791 return 'stored:{}:{}'.format(key, val)
@@ -1,1133 +1,1139 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%!
3 <%!
4 ## base64 filter e.g ${ example | base64 }
4 ## base64 filter e.g ${ example | base64 }
5 def base64(text):
5 def base64(text):
6 import base64
6 import base64
7 from rhodecode.lib.helpers import safe_str
7 from rhodecode.lib.helpers import safe_str
8 return base64.encodestring(safe_str(text))
8 return base64.encodestring(safe_str(text))
9 %>
9 %>
10
10
11 <%inherit file="root.mako"/>
11 <%inherit file="root.mako"/>
12
12
13 <%include file="/ejs_templates/templates.html"/>
13 <%include file="/ejs_templates/templates.html"/>
14
14
15 <div class="outerwrapper">
15 <div class="outerwrapper">
16 <!-- HEADER -->
16 <!-- HEADER -->
17 <div class="header">
17 <div class="header">
18 <div id="header-inner" class="wrapper">
18 <div id="header-inner" class="wrapper">
19 <div id="logo">
19 <div id="logo">
20 <div class="logo-wrapper">
20 <div class="logo-wrapper">
21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
22 </div>
22 </div>
23 % if c.rhodecode_name:
23 % if c.rhodecode_name:
24 <div class="branding">
24 <div class="branding">
25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
26 </div>
26 </div>
27 % endif
27 % endif
28 </div>
28 </div>
29 <!-- MENU BAR NAV -->
29 <!-- MENU BAR NAV -->
30 ${self.menu_bar_nav()}
30 ${self.menu_bar_nav()}
31 <!-- END MENU BAR NAV -->
31 <!-- END MENU BAR NAV -->
32 </div>
32 </div>
33 </div>
33 </div>
34 ${self.menu_bar_subnav()}
34 ${self.menu_bar_subnav()}
35 <!-- END HEADER -->
35 <!-- END HEADER -->
36
36
37 <!-- CONTENT -->
37 <!-- CONTENT -->
38 <div id="content" class="wrapper">
38 <div id="content" class="wrapper">
39
39
40 <rhodecode-toast id="notifications"></rhodecode-toast>
40 <rhodecode-toast id="notifications"></rhodecode-toast>
41
41
42 <div class="main">
42 <div class="main">
43 ${next.main()}
43 ${next.main()}
44 </div>
44 </div>
45 </div>
45 </div>
46 <!-- END CONTENT -->
46 <!-- END CONTENT -->
47
47
48 </div>
48 </div>
49 <!-- FOOTER -->
49 <!-- FOOTER -->
50 <div id="footer">
50 <div id="footer">
51 <div id="footer-inner" class="title wrapper">
51 <div id="footer-inner" class="title wrapper">
52 <div>
52 <div>
53 <p class="footer-link-right">
53 <p class="footer-link-right">
54 % if c.visual.show_version:
54 % if c.visual.show_version:
55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
56 % endif
56 % endif
57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
58 % if c.visual.rhodecode_support_url:
58 % if c.visual.rhodecode_support_url:
59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
60 % endif
60 % endif
61 </p>
61 </p>
62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
63 <p class="server-instance" style="display:${sid}">
63 <p class="server-instance" style="display:${sid}">
64 ## display hidden instance ID if specially defined
64 ## display hidden instance ID if specially defined
65 % if c.rhodecode_instanceid:
65 % if c.rhodecode_instanceid:
66 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
66 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
67 % endif
67 % endif
68 </p>
68 </p>
69 </div>
69 </div>
70 </div>
70 </div>
71 </div>
71 </div>
72
72
73 <!-- END FOOTER -->
73 <!-- END FOOTER -->
74
74
75 ### MAKO DEFS ###
75 ### MAKO DEFS ###
76
76
77 <%def name="menu_bar_subnav()">
77 <%def name="menu_bar_subnav()">
78 </%def>
78 </%def>
79
79
80 <%def name="breadcrumbs(class_='breadcrumbs')">
80 <%def name="breadcrumbs(class_='breadcrumbs')">
81 <div class="${class_}">
81 <div class="${class_}">
82 ${self.breadcrumbs_links()}
82 ${self.breadcrumbs_links()}
83 </div>
83 </div>
84 </%def>
84 </%def>
85
85
86 <%def name="admin_menu(active=None)">
86 <%def name="admin_menu(active=None)">
87
87
88 <div id="context-bar">
88 <div id="context-bar">
89 <div class="wrapper">
89 <div class="wrapper">
90 <div class="title">
90 <div class="title">
91 <div class="title-content">
91 <div class="title-content">
92 <div class="title-main">
92 <div class="title-main">
93 % if c.is_super_admin:
93 % if c.is_super_admin:
94 ${_('Super Admin Panel')}
94 ${_('Super Admin Panel')}
95 % else:
95 % else:
96 ${_('Delegated Admin Panel')}
96 ${_('Delegated Admin Panel')}
97 % endif
97 % endif
98 </div>
98 </div>
99 </div>
99 </div>
100 </div>
100 </div>
101
101
102 <ul id="context-pages" class="navigation horizontal-list">
102 <ul id="context-pages" class="navigation horizontal-list">
103
103
104 ## super admin case
104 ## super admin case
105 % if c.is_super_admin:
105 % if c.is_super_admin:
106 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
106 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
107 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
107 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
108 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
108 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
109 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
109 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
110 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
110 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
111 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
111 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
112 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
112 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
113 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
113 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
114 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
114 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
115 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
115 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
116
116
117 ## delegated admin
117 ## delegated admin
118 % elif c.is_delegated_admin:
118 % elif c.is_delegated_admin:
119 <%
119 <%
120 repositories=c.auth_user.repositories_admin or c.can_create_repo
120 repositories=c.auth_user.repositories_admin or c.can_create_repo
121 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
121 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
122 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
122 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
123 %>
123 %>
124
124
125 %if repositories:
125 %if repositories:
126 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
126 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
127 %endif
127 %endif
128 %if repository_groups:
128 %if repository_groups:
129 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
129 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
130 %endif
130 %endif
131 %if user_groups:
131 %if user_groups:
132 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
132 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
133 %endif
133 %endif
134 % endif
134 % endif
135 </ul>
135 </ul>
136
136
137 </div>
137 </div>
138 <div class="clear"></div>
138 <div class="clear"></div>
139 </div>
139 </div>
140 </%def>
140 </%def>
141
141
142 <%def name="dt_info_panel(elements)">
142 <%def name="dt_info_panel(elements)">
143 <dl class="dl-horizontal">
143 <dl class="dl-horizontal">
144 %for dt, dd, title, show_items in elements:
144 %for dt, dd, title, show_items in elements:
145 <dt>${dt}:</dt>
145 <dt>${dt}:</dt>
146 <dd title="${h.tooltip(title)}">
146 <dd title="${h.tooltip(title)}">
147 %if callable(dd):
147 %if callable(dd):
148 ## allow lazy evaluation of elements
148 ## allow lazy evaluation of elements
149 ${dd()}
149 ${dd()}
150 %else:
150 %else:
151 ${dd}
151 ${dd}
152 %endif
152 %endif
153 %if show_items:
153 %if show_items:
154 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
154 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
155 %endif
155 %endif
156 </dd>
156 </dd>
157
157
158 %if show_items:
158 %if show_items:
159 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
159 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
160 %for item in show_items:
160 %for item in show_items:
161 <dt></dt>
161 <dt></dt>
162 <dd>${item}</dd>
162 <dd>${item}</dd>
163 %endfor
163 %endfor
164 </div>
164 </div>
165 %endif
165 %endif
166
166
167 %endfor
167 %endfor
168 </dl>
168 </dl>
169 </%def>
169 </%def>
170
170
171 <%def name="tr_info_entry(element)">
171 <%def name="tr_info_entry(element)">
172 <% key, val, title, show_items = element %>
172 <% key, val, title, show_items = element %>
173
173
174 <tr>
174 <tr>
175 <td style="vertical-align: top">${key}</td>
175 <td style="vertical-align: top">${key}</td>
176 <td title="${h.tooltip(title)}">
176 <td title="${h.tooltip(title)}">
177 %if callable(val):
177 %if callable(val):
178 ## allow lazy evaluation of elements
178 ## allow lazy evaluation of elements
179 ${val()}
179 ${val()}
180 %else:
180 %else:
181 ${val}
181 ${val}
182 %endif
182 %endif
183 %if show_items:
183 %if show_items:
184 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
184 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
185 % for item in show_items:
185 % for item in show_items:
186 <dt></dt>
186 <dt></dt>
187 <dd>${item}</dd>
187 <dd>${item}</dd>
188 % endfor
188 % endfor
189 </div>
189 </div>
190 %endif
190 %endif
191 </td>
191 </td>
192 <td style="vertical-align: top">
192 <td style="vertical-align: top">
193 %if show_items:
193 %if show_items:
194 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
194 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
195 %endif
195 %endif
196 </td>
196 </td>
197 </tr>
197 </tr>
198
198
199 </%def>
199 </%def>
200
200
201 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None)">
201 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None)">
202 <%
202 <%
203 if size > 16:
203 if size > 16:
204 gravatar_class = ['gravatar','gravatar-large']
204 gravatar_class = ['gravatar','gravatar-large']
205 else:
205 else:
206 gravatar_class = ['gravatar']
206 gravatar_class = ['gravatar']
207
207
208 data_hovercard_url = ''
208 data_hovercard_url = ''
209 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
209 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
210
210
211 if tooltip:
211 if tooltip:
212 gravatar_class += ['tooltip-hovercard']
212 gravatar_class += ['tooltip-hovercard']
213
213
214 if tooltip and user:
214 if tooltip and user:
215 if user.username == h.DEFAULT_USER:
215 if user.username == h.DEFAULT_USER:
216 gravatar_class.pop(-1)
216 gravatar_class.pop(-1)
217 else:
217 else:
218 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
218 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
219 gravatar_class = ' '.join(gravatar_class)
219 gravatar_class = ' '.join(gravatar_class)
220
220
221 %>
221 %>
222 <%doc>
222 <%doc>
223 TODO: johbo: For now we serve double size images to make it smooth
223 TODO: johbo: For now we serve double size images to make it smooth
224 for retina. This is how it worked until now. Should be replaced
224 for retina. This is how it worked until now. Should be replaced
225 with a better solution at some point.
225 with a better solution at some point.
226 </%doc>
226 </%doc>
227
227
228 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
228 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
229 </%def>
229 </%def>
230
230
231
231
232 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)">
232 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)">
233 <%
233 <%
234 email = h.email_or_none(contact)
234 email = h.email_or_none(contact)
235 rc_user = h.discover_user(contact)
235 rc_user = h.discover_user(contact)
236 %>
236 %>
237
237
238 <div class="rc-user">
238 <div class="rc-user">
239 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
239 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
240 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
240 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
241 </div>
241 </div>
242 </%def>
242 </%def>
243
243
244
244
245 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
245 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
246 <%
246 <%
247 if (size > 16):
247 if (size > 16):
248 gravatar_class = 'icon-user-group-alt'
248 gravatar_class = 'icon-user-group-alt'
249 else:
249 else:
250 gravatar_class = 'icon-user-group-alt'
250 gravatar_class = 'icon-user-group-alt'
251
251
252 if tooltip:
252 if tooltip:
253 gravatar_class += ' tooltip-hovercard'
253 gravatar_class += ' tooltip-hovercard'
254
254
255 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
255 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
256 %>
256 %>
257 <%doc>
257 <%doc>
258 TODO: johbo: For now we serve double size images to make it smooth
258 TODO: johbo: For now we serve double size images to make it smooth
259 for retina. This is how it worked until now. Should be replaced
259 for retina. This is how it worked until now. Should be replaced
260 with a better solution at some point.
260 with a better solution at some point.
261 </%doc>
261 </%doc>
262
262
263 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
263 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
264 </%def>
264 </%def>
265
265
266 <%def name="repo_page_title(repo_instance)">
266 <%def name="repo_page_title(repo_instance)">
267 <div class="title-content repo-title">
267 <div class="title-content repo-title">
268
268
269 <div class="title-main">
269 <div class="title-main">
270 ## SVN/HG/GIT icons
270 ## SVN/HG/GIT icons
271 %if h.is_hg(repo_instance):
271 %if h.is_hg(repo_instance):
272 <i class="icon-hg"></i>
272 <i class="icon-hg"></i>
273 %endif
273 %endif
274 %if h.is_git(repo_instance):
274 %if h.is_git(repo_instance):
275 <i class="icon-git"></i>
275 <i class="icon-git"></i>
276 %endif
276 %endif
277 %if h.is_svn(repo_instance):
277 %if h.is_svn(repo_instance):
278 <i class="icon-svn"></i>
278 <i class="icon-svn"></i>
279 %endif
279 %endif
280
280
281 ## public/private
281 ## public/private
282 %if repo_instance.private:
282 %if repo_instance.private:
283 <i class="icon-repo-private"></i>
283 <i class="icon-repo-private"></i>
284 %else:
284 %else:
285 <i class="icon-repo-public"></i>
285 <i class="icon-repo-public"></i>
286 %endif
286 %endif
287
287
288 ## repo name with group name
288 ## repo name with group name
289 ${h.breadcrumb_repo_link(repo_instance)}
289 ${h.breadcrumb_repo_link(repo_instance)}
290
290
291 ## Context Actions
291 ## Context Actions
292 <div class="pull-right">
292 <div class="pull-right">
293 %if c.rhodecode_user.username != h.DEFAULT_USER:
293 %if c.rhodecode_user.username != h.DEFAULT_USER:
294 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
294 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
295
295
296 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
296 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
297 % if c.repository_is_user_following:
297 % if c.repository_is_user_following:
298 <i class="icon-eye-off"></i>${_('Unwatch')}
298 <i class="icon-eye-off"></i>${_('Unwatch')}
299 % else:
299 % else:
300 <i class="icon-eye"></i>${_('Watch')}
300 <i class="icon-eye"></i>${_('Watch')}
301 % endif
301 % endif
302
302
303 </a>
303 </a>
304 %else:
304 %else:
305 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
305 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
306 %endif
306 %endif
307 </div>
307 </div>
308
308
309 </div>
309 </div>
310
310
311 ## FORKED
311 ## FORKED
312 %if repo_instance.fork:
312 %if repo_instance.fork:
313 <p class="discreet">
313 <p class="discreet">
314 <i class="icon-code-fork"></i> ${_('Fork of')}
314 <i class="icon-code-fork"></i> ${_('Fork of')}
315 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
315 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
316 </p>
316 </p>
317 %endif
317 %endif
318
318
319 ## IMPORTED FROM REMOTE
319 ## IMPORTED FROM REMOTE
320 %if repo_instance.clone_uri:
320 %if repo_instance.clone_uri:
321 <p class="discreet">
321 <p class="discreet">
322 <i class="icon-code-fork"></i> ${_('Clone from')}
322 <i class="icon-code-fork"></i> ${_('Clone from')}
323 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
323 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
324 </p>
324 </p>
325 %endif
325 %endif
326
326
327 ## LOCKING STATUS
327 ## LOCKING STATUS
328 %if repo_instance.locked[0]:
328 %if repo_instance.locked[0]:
329 <p class="locking_locked discreet">
329 <p class="locking_locked discreet">
330 <i class="icon-repo-lock"></i>
330 <i class="icon-repo-lock"></i>
331 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
331 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
332 </p>
332 </p>
333 %elif repo_instance.enable_locking:
333 %elif repo_instance.enable_locking:
334 <p class="locking_unlocked discreet">
334 <p class="locking_unlocked discreet">
335 <i class="icon-repo-unlock"></i>
335 <i class="icon-repo-unlock"></i>
336 ${_('Repository not locked. Pull repository to lock it.')}
336 ${_('Repository not locked. Pull repository to lock it.')}
337 </p>
337 </p>
338 %endif
338 %endif
339
339
340 </div>
340 </div>
341 </%def>
341 </%def>
342
342
343 <%def name="repo_menu(active=None)">
343 <%def name="repo_menu(active=None)">
344 <%
344 <%
345 ## determine if we have "any" option available
345 ## determine if we have "any" option available
346 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
346 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
347 has_actions = can_lock
347 has_actions = can_lock
348
348
349 %>
349 %>
350 % if c.rhodecode_db_repo.archived:
350 % if c.rhodecode_db_repo.archived:
351 <div class="alert alert-warning text-center">
351 <div class="alert alert-warning text-center">
352 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
352 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
353 </div>
353 </div>
354 % endif
354 % endif
355
355
356 <!--- REPO CONTEXT BAR -->
356 <!--- REPO CONTEXT BAR -->
357 <div id="context-bar">
357 <div id="context-bar">
358 <div class="wrapper">
358 <div class="wrapper">
359
359
360 <div class="title">
360 <div class="title">
361 ${self.repo_page_title(c.rhodecode_db_repo)}
361 ${self.repo_page_title(c.rhodecode_db_repo)}
362 </div>
362 </div>
363
363
364 <ul id="context-pages" class="navigation horizontal-list">
364 <ul id="context-pages" class="navigation horizontal-list">
365 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
365 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
366 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
366 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
367 <li class="${h.is_active('files', active)}"><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>
367 <li class="${h.is_active('files', active)}"><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>
368 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
368 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
369
369
370 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
370 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
371 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
371 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
372 <li class="${h.is_active('showpullrequest', active)}">
372 <li class="${h.is_active('showpullrequest', active)}">
373 <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)}">
373 <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)}">
374 <div class="menulabel">
374 <div class="menulabel">
375 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
375 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
376 </div>
376 </div>
377 </a>
377 </a>
378 </li>
378 </li>
379 %endif
379 %endif
380
380
381 <li class="${h.is_active('artifacts', active)}">
381 <li class="${h.is_active('artifacts', active)}">
382 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
382 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
383 <div class="menulabel">
383 <div class="menulabel">
384 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
384 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
385 </div>
385 </div>
386 </a>
386 </a>
387 </li>
387 </li>
388
388
389 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
389 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
390 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
390 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
391 %endif
391 %endif
392
392
393 <li class="${h.is_active('options', active)}">
393 <li class="${h.is_active('options', active)}">
394 % if has_actions:
394 % if has_actions:
395 <a class="menulink dropdown">
395 <a class="menulink dropdown">
396 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
396 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
397 </a>
397 </a>
398 <ul class="submenu">
398 <ul class="submenu">
399 %if can_lock:
399 %if can_lock:
400 %if c.rhodecode_db_repo.locked[0]:
400 %if c.rhodecode_db_repo.locked[0]:
401 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
401 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
402 %else:
402 %else:
403 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
403 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
404 %endif
404 %endif
405 %endif
405 %endif
406 </ul>
406 </ul>
407 % else:
407 % else:
408 <a class="menulink disabled">
408 <a class="menulink disabled">
409 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
409 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
410 </a>
410 </a>
411 % endif
411 % endif
412 </li>
412 </li>
413
413
414 </ul>
414 </ul>
415 </div>
415 </div>
416 <div class="clear"></div>
416 <div class="clear"></div>
417 </div>
417 </div>
418
418
419 <!--- REPO END CONTEXT BAR -->
419 <!--- REPO END CONTEXT BAR -->
420
420
421 </%def>
421 </%def>
422
422
423 <%def name="repo_group_page_title(repo_group_instance)">
423 <%def name="repo_group_page_title(repo_group_instance)">
424 <div class="title-content">
424 <div class="title-content">
425 <div class="title-main">
425 <div class="title-main">
426 ## Repository Group icon
426 ## Repository Group icon
427 <i class="icon-repo-group"></i>
427 <i class="icon-repo-group"></i>
428
428
429 ## repo name with group name
429 ## repo name with group name
430 ${h.breadcrumb_repo_group_link(repo_group_instance)}
430 ${h.breadcrumb_repo_group_link(repo_group_instance)}
431 </div>
431 </div>
432
432
433 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
433 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
434 <div class="repo-group-desc discreet">
434 <div class="repo-group-desc discreet">
435 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
435 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
436 </div>
436 </div>
437
437
438 </div>
438 </div>
439 </%def>
439 </%def>
440
440
441
441
442 <%def name="repo_group_menu(active=None)">
442 <%def name="repo_group_menu(active=None)">
443 <%
443 <%
444 gr_name = c.repo_group.group_name if c.repo_group else None
444 gr_name = c.repo_group.group_name if c.repo_group else None
445 # create repositories with write permission on group is set to true
445 # create repositories with write permission on group is set to true
446 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
446 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
447
447
448 %>
448 %>
449
449
450
450
451 <!--- REPO GROUP CONTEXT BAR -->
451 <!--- REPO GROUP CONTEXT BAR -->
452 <div id="context-bar">
452 <div id="context-bar">
453 <div class="wrapper">
453 <div class="wrapper">
454 <div class="title">
454 <div class="title">
455 ${self.repo_group_page_title(c.repo_group)}
455 ${self.repo_group_page_title(c.repo_group)}
456 </div>
456 </div>
457
457
458 <ul id="context-pages" class="navigation horizontal-list">
458 <ul id="context-pages" class="navigation horizontal-list">
459 <li class="${h.is_active('home', active)}">
459 <li class="${h.is_active('home', active)}">
460 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
460 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
461 </li>
461 </li>
462 % if c.is_super_admin or group_admin:
462 % if c.is_super_admin or group_admin:
463 <li class="${h.is_active('settings', active)}">
463 <li class="${h.is_active('settings', active)}">
464 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
464 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
465 </li>
465 </li>
466 % endif
466 % endif
467
467
468 </ul>
468 </ul>
469 </div>
469 </div>
470 <div class="clear"></div>
470 <div class="clear"></div>
471 </div>
471 </div>
472
472
473 <!--- REPO GROUP CONTEXT BAR -->
473 <!--- REPO GROUP CONTEXT BAR -->
474
474
475 </%def>
475 </%def>
476
476
477
477
478 <%def name="usermenu(active=False)">
478 <%def name="usermenu(active=False)">
479 <%
479 <%
480 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
480 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
481
481
482 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
482 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
483 # create repositories with write permission on group is set to true
483 # create repositories with write permission on group is set to true
484
484
485 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
485 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
486 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
486 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
487 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
487 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
488 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
488 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
489
489
490 can_create_repos = c.is_super_admin or c.can_create_repo
490 can_create_repos = c.is_super_admin or c.can_create_repo
491 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
491 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
492
492
493 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
493 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
494 can_create_repo_groups_in_group = c.is_super_admin or group_admin
494 can_create_repo_groups_in_group = c.is_super_admin or group_admin
495 %>
495 %>
496
496
497 % if not_anonymous:
497 % if not_anonymous:
498 <%
498 <%
499 default_target_group = dict()
499 default_target_group = dict()
500 if c.rhodecode_user.personal_repo_group:
500 if c.rhodecode_user.personal_repo_group:
501 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
501 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
502 %>
502 %>
503
503
504 ## create action
504 ## create action
505 <li>
505 <li>
506 <a href="#create-actions" onclick="return false;" class="menulink childs">
506 <a href="#create-actions" onclick="return false;" class="menulink childs">
507 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
507 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
508 </a>
508 </a>
509
509
510 <div class="action-menu submenu">
510 <div class="action-menu submenu">
511
511
512 <ol>
512 <ol>
513 ## scope of within a repository
513 ## scope of within a repository
514 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
514 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
515 <li class="submenu-title">${_('This Repository')}</li>
515 <li class="submenu-title">${_('This Repository')}</li>
516 <li>
516 <li>
517 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
517 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
518 </li>
518 </li>
519 % if can_fork:
519 % if can_fork:
520 <li>
520 <li>
521 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
521 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
522 </li>
522 </li>
523 % endif
523 % endif
524 % endif
524 % endif
525
525
526 ## scope of within repository groups
526 ## scope of within repository groups
527 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
527 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
528 <li class="submenu-title">${_('This Repository Group')}</li>
528 <li class="submenu-title">${_('This Repository Group')}</li>
529
529
530 % if can_create_repos_in_group:
530 % if can_create_repos_in_group:
531 <li>
531 <li>
532 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
532 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
533 </li>
533 </li>
534 % endif
534 % endif
535
535
536 % if can_create_repo_groups_in_group:
536 % if can_create_repo_groups_in_group:
537 <li>
537 <li>
538 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
538 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
539 </li>
539 </li>
540 % endif
540 % endif
541 % endif
541 % endif
542
542
543 ## personal group
543 ## personal group
544 % if c.rhodecode_user.personal_repo_group:
544 % if c.rhodecode_user.personal_repo_group:
545 <li class="submenu-title">Personal Group</li>
545 <li class="submenu-title">Personal Group</li>
546
546
547 <li>
547 <li>
548 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
548 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
549 </li>
549 </li>
550
550
551 <li>
551 <li>
552 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
552 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
553 </li>
553 </li>
554 % endif
554 % endif
555
555
556 ## Global actions
556 ## Global actions
557 <li class="submenu-title">RhodeCode</li>
557 <li class="submenu-title">RhodeCode</li>
558 % if can_create_repos:
558 % if can_create_repos:
559 <li>
559 <li>
560 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
560 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
561 </li>
561 </li>
562 % endif
562 % endif
563
563
564 % if can_create_repo_groups:
564 % if can_create_repo_groups:
565 <li>
565 <li>
566 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
566 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
567 </li>
567 </li>
568 % endif
568 % endif
569
569
570 <li>
570 <li>
571 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
571 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
572 </li>
572 </li>
573
573
574 </ol>
574 </ol>
575
575
576 </div>
576 </div>
577 </li>
577 </li>
578
578
579 ## notifications
579 ## notifications
580 <li>
580 <li>
581 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
581 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
582 ${c.unread_notifications}
582 ${c.unread_notifications}
583 </a>
583 </a>
584 </li>
584 </li>
585 % endif
585 % endif
586
586
587 ## USER MENU
587 ## USER MENU
588 <li id="quick_login_li" class="${'active' if active else ''}">
588 <li id="quick_login_li" class="${'active' if active else ''}">
589 % if c.rhodecode_user.username == h.DEFAULT_USER:
589 % if c.rhodecode_user.username == h.DEFAULT_USER:
590 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
590 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
591 ${gravatar(c.rhodecode_user.email, 20)}
591 ${gravatar(c.rhodecode_user.email, 20)}
592 <span class="user">
592 <span class="user">
593 <span>${_('Sign in')}</span>
593 <span>${_('Sign in')}</span>
594 </span>
594 </span>
595 </a>
595 </a>
596 % else:
596 % else:
597 ## logged in user
597 ## logged in user
598 <a id="quick_login_link" class="menulink childs">
598 <a id="quick_login_link" class="menulink childs">
599 ${gravatar(c.rhodecode_user.email, 20)}
599 ${gravatar(c.rhodecode_user.email, 20)}
600 <span class="user">
600 <span class="user">
601 <span class="menu_link_user">${c.rhodecode_user.username}</span>
601 <span class="menu_link_user">${c.rhodecode_user.username}</span>
602 <div class="show_more"></div>
602 <div class="show_more"></div>
603 </span>
603 </span>
604 </a>
604 </a>
605 ## subnav with menu for logged in user
605 ## subnav with menu for logged in user
606 <div class="user-menu submenu">
606 <div class="user-menu submenu">
607 <div id="quick_login">
607 <div id="quick_login">
608 %if c.rhodecode_user.username != h.DEFAULT_USER:
608 %if c.rhodecode_user.username != h.DEFAULT_USER:
609 <div class="">
609 <div class="">
610 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
610 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
611 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
611 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
612 <div class="email">${c.rhodecode_user.email}</div>
612 <div class="email">${c.rhodecode_user.email}</div>
613 </div>
613 </div>
614 <div class="">
614 <div class="">
615 <ol class="links">
615 <ol class="links">
616 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
616 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
617 % if c.rhodecode_user.personal_repo_group:
617 % if c.rhodecode_user.personal_repo_group:
618 <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>
618 <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>
619 % endif
619 % endif
620 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
620 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
621
621
622 % if c.debug_style:
622 % if c.debug_style:
623 <li>
623 <li>
624 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
624 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
625 <div class="menulabel">${_('[Style]')}</div>
625 <div class="menulabel">${_('[Style]')}</div>
626 </a>
626 </a>
627 </li>
627 </li>
628 % endif
628 % endif
629
629
630 ## bookmark-items
630 ## bookmark-items
631 <li class="bookmark-items">
631 <li class="bookmark-items">
632 ${_('Bookmarks')}
632 ${_('Bookmarks')}
633 <div class="pull-right">
633 <div class="pull-right">
634 <a href="${h.route_path('my_account_bookmarks')}">
634 <a href="${h.route_path('my_account_bookmarks')}">
635
635
636 <i class="icon-cog"></i>
636 <i class="icon-cog"></i>
637 </a>
637 </a>
638 </div>
638 </div>
639 </li>
639 </li>
640 % if not c.bookmark_items:
640 % if not c.bookmark_items:
641 <li>
641 <li>
642 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
642 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
643 </li>
643 </li>
644 % endif
644 % endif
645 % for item in c.bookmark_items:
645 % for item in c.bookmark_items:
646 <li>
646 <li>
647 % if item.repository:
647 % if item.repository:
648 <div>
648 <div>
649 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
649 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
650 <code>${item.position}</code>
650 <code>${item.position}</code>
651 % if item.repository.repo_type == 'hg':
651 % if item.repository.repo_type == 'hg':
652 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
652 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
653 % elif item.repository.repo_type == 'git':
653 % elif item.repository.repo_type == 'git':
654 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
654 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
655 % elif item.repository.repo_type == 'svn':
655 % elif item.repository.repo_type == 'svn':
656 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
656 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
657 % endif
657 % endif
658 ${(item.title or h.shorter(item.repository.repo_name, 30))}
658 ${(item.title or h.shorter(item.repository.repo_name, 30))}
659 </a>
659 </a>
660 </div>
660 </div>
661 % elif item.repository_group:
661 % elif item.repository_group:
662 <div>
662 <div>
663 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
663 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
664 <code>${item.position}</code>
664 <code>${item.position}</code>
665 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
665 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
666 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
666 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
667 </a>
667 </a>
668 </div>
668 </div>
669 % else:
669 % else:
670 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
670 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
671 <code>${item.position}</code>
671 <code>${item.position}</code>
672 ${item.title}
672 ${item.title}
673 </a>
673 </a>
674 % endif
674 % endif
675 </li>
675 </li>
676 % endfor
676 % endfor
677
677
678 <li class="logout">
678 <li class="logout">
679 ${h.secure_form(h.route_path('logout'), request=request)}
679 ${h.secure_form(h.route_path('logout'), request=request)}
680 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
680 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
681 ${h.end_form()}
681 ${h.end_form()}
682 </li>
682 </li>
683 </ol>
683 </ol>
684 </div>
684 </div>
685 %endif
685 %endif
686 </div>
686 </div>
687 </div>
687 </div>
688
688
689 % endif
689 % endif
690 </li>
690 </li>
691 </%def>
691 </%def>
692
692
693 <%def name="menu_items(active=None)">
693 <%def name="menu_items(active=None)">
694
694
695 <ul id="quick" class="main_nav navigation horizontal-list">
695 <ul id="quick" class="main_nav navigation horizontal-list">
696 ## notice box for important system messages
696 ## notice box for important system messages
697 <li style="display: none">
697 <li style="display: none">
698 <a class="notice-box" href="#openNotice" onclick="return false">
698 <a class="notice-box" href="#openNotice" onclick="return false">
699 <div class="menulabel-notice" >
699 <div class="menulabel-notice" >
700 0
700 0
701 </div>
701 </div>
702 </a>
702 </a>
703 </li>
703 </li>
704
704
705 ## Main filter
705 ## Main filter
706 <li>
706 <li>
707 <div class="menulabel main_filter_box">
707 <div class="menulabel main_filter_box">
708 <div class="main_filter_input_box">
708 <div class="main_filter_input_box">
709 <ul class="searchItems">
709 <ul class="searchItems">
710
710
711 <li class="searchTag searchTagIcon">
711 <li class="searchTag searchTagIcon">
712 <i class="icon-search"></i>
712 <i class="icon-search"></i>
713 </li>
713 </li>
714
714
715 % if c.template_context['search_context']['repo_id']:
715 % if c.template_context['search_context']['repo_id']:
716 <li class="searchTag searchTagFilter searchTagHidable" >
716 <li class="searchTag searchTagFilter searchTagHidable" >
717 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
717 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
718 <span class="tag">
718 <span class="tag">
719 This repo
719 This repo
720 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
720 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
721 </span>
721 </span>
722 ##</a>
722 ##</a>
723 </li>
723 </li>
724 % elif c.template_context['search_context']['repo_group_id']:
724 % elif c.template_context['search_context']['repo_group_id']:
725 <li class="searchTag searchTagFilter searchTagHidable">
725 <li class="searchTag searchTagFilter searchTagHidable">
726 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
726 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
727 <span class="tag">
727 <span class="tag">
728 This group
728 This group
729 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
729 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
730 </span>
730 </span>
731 ##</a>
731 ##</a>
732 </li>
732 </li>
733 % endif
733 % endif
734
734
735 <li class="searchTagInput">
735 <li class="searchTagInput">
736 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
736 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
737 </li>
737 </li>
738 <li class="searchTag searchTagHelp">
738 <li class="searchTag searchTagHelp">
739 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
739 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
740 </li>
740 </li>
741 </ul>
741 </ul>
742 </div>
742 </div>
743 </div>
743 </div>
744
744
745 <div id="main_filter_help" style="display: none">
745 <div id="main_filter_help" style="display: none">
746 - Use '/' key to quickly access this field.
746 - Use '/' key to quickly access this field.
747
747
748 - Enter a name of repository, or repository group for quick search.
748 - Enter a name of repository, or repository group for quick search.
749
749
750 - Prefix query to allow special search:
750 - Prefix query to allow special search:
751
751
752 user:admin, to search for usernames, always global
752 user:admin, to search for usernames, always global
753
753
754 user_group:devops, to search for user groups, always global
754 user_group:devops, to search for user groups, always global
755
755
756 commit:efced4, to search for commits, scoped to repositories or groups
756 commit:efced4, to search for commits, scoped to repositories or groups
757
757
758 file:models.py, to search for file paths, scoped to repositories or groups
758 file:models.py, to search for file paths, scoped to repositories or groups
759
759
760 % if c.template_context['search_context']['repo_id']:
760 % if c.template_context['search_context']['repo_id']:
761 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
761 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
762 % elif c.template_context['search_context']['repo_group_id']:
762 % elif c.template_context['search_context']['repo_group_id']:
763 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
763 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
764 % else:
764 % else:
765 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
765 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
766 % endif
766 % endif
767 </div>
767 </div>
768 </li>
768 </li>
769
769
770 ## ROOT MENU
770 ## ROOT MENU
771 <li class="${h.is_active('home', active)}">
771 <li class="${h.is_active('home', active)}">
772 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
772 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
773 <div class="menulabel">${_('Home')}</div>
773 <div class="menulabel">${_('Home')}</div>
774 </a>
774 </a>
775 </li>
775 </li>
776
776
777 %if c.rhodecode_user.username != h.DEFAULT_USER:
777 %if c.rhodecode_user.username != h.DEFAULT_USER:
778 <li class="${h.is_active('journal', active)}">
778 <li class="${h.is_active('journal', active)}">
779 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
779 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
780 <div class="menulabel">${_('Journal')}</div>
780 <div class="menulabel">${_('Journal')}</div>
781 </a>
781 </a>
782 </li>
782 </li>
783 %else:
783 %else:
784 <li class="${h.is_active('journal', active)}">
784 <li class="${h.is_active('journal', active)}">
785 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
785 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
786 <div class="menulabel">${_('Public journal')}</div>
786 <div class="menulabel">${_('Public journal')}</div>
787 </a>
787 </a>
788 </li>
788 </li>
789 %endif
789 %endif
790
790
791 <li class="${h.is_active('gists', active)}">
791 <li class="${h.is_active('gists', active)}">
792 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
792 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
793 <div class="menulabel">${_('Gists')}</div>
793 <div class="menulabel">${_('Gists')}</div>
794 </a>
794 </a>
795 </li>
795 </li>
796
796
797 % if c.is_super_admin or c.is_delegated_admin:
797 % if c.is_super_admin or c.is_delegated_admin:
798 <li class="${h.is_active('admin', active)}">
798 <li class="${h.is_active('admin', active)}">
799 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
799 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
800 <div class="menulabel">${_('Admin')} </div>
800 <div class="menulabel">${_('Admin')} </div>
801 </a>
801 </a>
802 </li>
802 </li>
803 % endif
803 % endif
804
804
805 ## render extra user menu
805 ## render extra user menu
806 ${usermenu(active=(active=='my_account'))}
806 ${usermenu(active=(active=='my_account'))}
807
807
808 </ul>
808 </ul>
809
809
810 <script type="text/javascript">
810 <script type="text/javascript">
811 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
811 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
812
812
813 var formatRepoResult = function(result, container, query, escapeMarkup) {
813 var formatRepoResult = function(result, container, query, escapeMarkup) {
814 return function(data, escapeMarkup) {
814 return function(data, escapeMarkup) {
815 if (!data.repo_id){
815 if (!data.repo_id){
816 return data.text; // optgroup text Repositories
816 return data.text; // optgroup text Repositories
817 }
817 }
818
818
819 var tmpl = '';
819 var tmpl = '';
820 var repoType = data['repo_type'];
820 var repoType = data['repo_type'];
821 var repoName = data['text'];
821 var repoName = data['text'];
822
822
823 if(data && data.type == 'repo'){
823 if(data && data.type == 'repo'){
824 if(repoType === 'hg'){
824 if(repoType === 'hg'){
825 tmpl += '<i class="icon-hg"></i> ';
825 tmpl += '<i class="icon-hg"></i> ';
826 }
826 }
827 else if(repoType === 'git'){
827 else if(repoType === 'git'){
828 tmpl += '<i class="icon-git"></i> ';
828 tmpl += '<i class="icon-git"></i> ';
829 }
829 }
830 else if(repoType === 'svn'){
830 else if(repoType === 'svn'){
831 tmpl += '<i class="icon-svn"></i> ';
831 tmpl += '<i class="icon-svn"></i> ';
832 }
832 }
833 if(data['private']){
833 if(data['private']){
834 tmpl += '<i class="icon-lock" ></i> ';
834 tmpl += '<i class="icon-lock" ></i> ';
835 }
835 }
836 else if(visualShowPublicIcon){
836 else if(visualShowPublicIcon){
837 tmpl += '<i class="icon-unlock-alt"></i> ';
837 tmpl += '<i class="icon-unlock-alt"></i> ';
838 }
838 }
839 }
839 }
840 tmpl += escapeMarkup(repoName);
840 tmpl += escapeMarkup(repoName);
841 return tmpl;
841 return tmpl;
842
842
843 }(result, escapeMarkup);
843 }(result, escapeMarkup);
844 };
844 };
845
845
846 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
846 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
847 return function(data, escapeMarkup) {
847 return function(data, escapeMarkup) {
848 if (!data.repo_group_id){
848 if (!data.repo_group_id){
849 return data.text; // optgroup text Repositories
849 return data.text; // optgroup text Repositories
850 }
850 }
851
851
852 var tmpl = '';
852 var tmpl = '';
853 var repoGroupName = data['text'];
853 var repoGroupName = data['text'];
854
854
855 if(data){
855 if(data){
856
856
857 tmpl += '<i class="icon-repo-group"></i> ';
857 tmpl += '<i class="icon-repo-group"></i> ';
858
858
859 }
859 }
860 tmpl += escapeMarkup(repoGroupName);
860 tmpl += escapeMarkup(repoGroupName);
861 return tmpl;
861 return tmpl;
862
862
863 }(result, escapeMarkup);
863 }(result, escapeMarkup);
864 };
864 };
865
865
866 var escapeRegExChars = function (value) {
866 var escapeRegExChars = function (value) {
867 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
867 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
868 };
868 };
869
869
870 var getRepoIcon = function(repo_type) {
870 var getRepoIcon = function(repo_type) {
871 if (repo_type === 'hg') {
871 if (repo_type === 'hg') {
872 return '<i class="icon-hg"></i> ';
872 return '<i class="icon-hg"></i> ';
873 }
873 }
874 else if (repo_type === 'git') {
874 else if (repo_type === 'git') {
875 return '<i class="icon-git"></i> ';
875 return '<i class="icon-git"></i> ';
876 }
876 }
877 else if (repo_type === 'svn') {
877 else if (repo_type === 'svn') {
878 return '<i class="icon-svn"></i> ';
878 return '<i class="icon-svn"></i> ';
879 }
879 }
880 return ''
880 return ''
881 };
881 };
882
882
883 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
883 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
884
884
885 if (value.split(':').length === 2) {
885 if (value.split(':').length === 2) {
886 value = value.split(':')[1]
886 value = value.split(':')[1]
887 }
887 }
888
888
889 var searchType = data['type'];
889 var searchType = data['type'];
890 var searchSubType = data['subtype'];
890 var searchSubType = data['subtype'];
891 var valueDisplay = data['value_display'];
891 var valueDisplay = data['value_display'];
892 var valueIcon = data['value_icon'];
892
893
893 var pattern = '(' + escapeRegExChars(value) + ')';
894 var pattern = '(' + escapeRegExChars(value) + ')';
894
895
895 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
896 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
896
897
897 // highlight match
898 // highlight match
898 if (searchType != 'text') {
899 if (searchType != 'text') {
899 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
900 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
900 }
901 }
901
902
902 var icon = '';
903 var icon = '';
903
904
904 if (searchType === 'hint') {
905 if (searchType === 'hint') {
905 icon += '<i class="icon-repo-group"></i> ';
906 icon += '<i class="icon-repo-group"></i> ';
906 }
907 }
907 // full text search/hints
908 // full text search/hints
908 else if (searchType === 'search') {
909 else if (searchType === 'search') {
910 if (valueIcon === undefined) {
909 icon += '<i class="icon-more"></i> ';
911 icon += '<i class="icon-more"></i> ';
912 } else {
913 icon += valueIcon + ' ';
914 }
915
910 if (searchSubType !== undefined && searchSubType == 'repo') {
916 if (searchSubType !== undefined && searchSubType == 'repo') {
911 valueDisplay += '<div class="pull-right tag">repository</div>';
917 valueDisplay += '<div class="pull-right tag">repository</div>';
912 }
918 }
913 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
919 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
914 valueDisplay += '<div class="pull-right tag">repo group</div>';
920 valueDisplay += '<div class="pull-right tag">repo group</div>';
915 }
921 }
916 }
922 }
917 // repository
923 // repository
918 else if (searchType === 'repo') {
924 else if (searchType === 'repo') {
919
925
920 var repoIcon = getRepoIcon(data['repo_type']);
926 var repoIcon = getRepoIcon(data['repo_type']);
921 icon += repoIcon;
927 icon += repoIcon;
922
928
923 if (data['private']) {
929 if (data['private']) {
924 icon += '<i class="icon-lock" ></i> ';
930 icon += '<i class="icon-lock" ></i> ';
925 }
931 }
926 else if (visualShowPublicIcon) {
932 else if (visualShowPublicIcon) {
927 icon += '<i class="icon-unlock-alt"></i> ';
933 icon += '<i class="icon-unlock-alt"></i> ';
928 }
934 }
929 }
935 }
930 // repository groups
936 // repository groups
931 else if (searchType === 'repo_group') {
937 else if (searchType === 'repo_group') {
932 icon += '<i class="icon-repo-group"></i> ';
938 icon += '<i class="icon-repo-group"></i> ';
933 }
939 }
934 // user group
940 // user group
935 else if (searchType === 'user_group') {
941 else if (searchType === 'user_group') {
936 icon += '<i class="icon-group"></i> ';
942 icon += '<i class="icon-group"></i> ';
937 }
943 }
938 // user
944 // user
939 else if (searchType === 'user') {
945 else if (searchType === 'user') {
940 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
946 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
941 }
947 }
942 // commit
948 // commit
943 else if (searchType === 'commit') {
949 else if (searchType === 'commit') {
944 var repo_data = data['repo_data'];
950 var repo_data = data['repo_data'];
945 var repoIcon = getRepoIcon(repo_data['repository_type']);
951 var repoIcon = getRepoIcon(repo_data['repository_type']);
946 if (repoIcon) {
952 if (repoIcon) {
947 icon += repoIcon;
953 icon += repoIcon;
948 } else {
954 } else {
949 icon += '<i class="icon-tag"></i>';
955 icon += '<i class="icon-tag"></i>';
950 }
956 }
951 }
957 }
952 // file
958 // file
953 else if (searchType === 'file') {
959 else if (searchType === 'file') {
954 var repo_data = data['repo_data'];
960 var repo_data = data['repo_data'];
955 var repoIcon = getRepoIcon(repo_data['repository_type']);
961 var repoIcon = getRepoIcon(repo_data['repository_type']);
956 if (repoIcon) {
962 if (repoIcon) {
957 icon += repoIcon;
963 icon += repoIcon;
958 } else {
964 } else {
959 icon += '<i class="icon-tag"></i>';
965 icon += '<i class="icon-tag"></i>';
960 }
966 }
961 }
967 }
962 // generic text
968 // generic text
963 else if (searchType === 'text') {
969 else if (searchType === 'text') {
964 icon = '';
970 icon = '';
965 }
971 }
966
972
967 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
973 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
968 return tmpl.format(icon, valueDisplay);
974 return tmpl.format(icon, valueDisplay);
969 };
975 };
970
976
971 var handleSelect = function(element, suggestion) {
977 var handleSelect = function(element, suggestion) {
972 if (suggestion.type === "hint") {
978 if (suggestion.type === "hint") {
973 // we skip action
979 // we skip action
974 $('#main_filter').focus();
980 $('#main_filter').focus();
975 }
981 }
976 else if (suggestion.type === "text") {
982 else if (suggestion.type === "text") {
977 // we skip action
983 // we skip action
978 $('#main_filter').focus();
984 $('#main_filter').focus();
979
985
980 } else {
986 } else {
981 window.location = suggestion['url'];
987 window.location = suggestion['url'];
982 }
988 }
983 };
989 };
984
990
985 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
991 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
986 if (queryLowerCase.split(':').length === 2) {
992 if (queryLowerCase.split(':').length === 2) {
987 queryLowerCase = queryLowerCase.split(':')[1]
993 queryLowerCase = queryLowerCase.split(':')[1]
988 }
994 }
989 if (suggestion.type === "text") {
995 if (suggestion.type === "text") {
990 // special case we don't want to "skip" display for
996 // special case we don't want to "skip" display for
991 return true
997 return true
992 }
998 }
993 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
999 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
994 };
1000 };
995
1001
996 var cleanContext = {
1002 var cleanContext = {
997 repo_view_type: null,
1003 repo_view_type: null,
998
1004
999 repo_id: null,
1005 repo_id: null,
1000 repo_name: "",
1006 repo_name: "",
1001
1007
1002 repo_group_id: null,
1008 repo_group_id: null,
1003 repo_group_name: null
1009 repo_group_name: null
1004 };
1010 };
1005 var removeGoToFilter = function () {
1011 var removeGoToFilter = function () {
1006 $('.searchTagHidable').hide();
1012 $('.searchTagHidable').hide();
1007 $('#main_filter').autocomplete(
1013 $('#main_filter').autocomplete(
1008 'setOptions', {params:{search_context: cleanContext}});
1014 'setOptions', {params:{search_context: cleanContext}});
1009 };
1015 };
1010
1016
1011 $('#main_filter').autocomplete({
1017 $('#main_filter').autocomplete({
1012 serviceUrl: pyroutes.url('goto_switcher_data'),
1018 serviceUrl: pyroutes.url('goto_switcher_data'),
1013 params: {
1019 params: {
1014 "search_context": templateContext.search_context
1020 "search_context": templateContext.search_context
1015 },
1021 },
1016 minChars:2,
1022 minChars:2,
1017 maxHeight:400,
1023 maxHeight:400,
1018 deferRequestBy: 300, //miliseconds
1024 deferRequestBy: 300, //miliseconds
1019 tabDisabled: true,
1025 tabDisabled: true,
1020 autoSelectFirst: false,
1026 autoSelectFirst: false,
1021 containerClass: 'autocomplete-qfilter-suggestions',
1027 containerClass: 'autocomplete-qfilter-suggestions',
1022 formatResult: autocompleteMainFilterFormatResult,
1028 formatResult: autocompleteMainFilterFormatResult,
1023 lookupFilter: autocompleteMainFilterResult,
1029 lookupFilter: autocompleteMainFilterResult,
1024 onSelect: function (element, suggestion) {
1030 onSelect: function (element, suggestion) {
1025 handleSelect(element, suggestion);
1031 handleSelect(element, suggestion);
1026 return false;
1032 return false;
1027 },
1033 },
1028 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1034 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1029 if (jqXHR !== 'abort') {
1035 if (jqXHR !== 'abort') {
1030 alert("Error during search.\nError code: {0}".format(textStatus));
1036 alert("Error during search.\nError code: {0}".format(textStatus));
1031 window.location = '';
1037 window.location = '';
1032 }
1038 }
1033 },
1039 },
1034 onSearchStart: function (params) {
1040 onSearchStart: function (params) {
1035 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1041 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1036 },
1042 },
1037 onSearchComplete: function (query, suggestions) {
1043 onSearchComplete: function (query, suggestions) {
1038 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1044 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1039 },
1045 },
1040 });
1046 });
1041
1047
1042 showMainFilterBox = function () {
1048 showMainFilterBox = function () {
1043 $('#main_filter_help').toggle();
1049 $('#main_filter_help').toggle();
1044 };
1050 };
1045
1051
1046 $('#main_filter').on('keydown.autocomplete', function (e) {
1052 $('#main_filter').on('keydown.autocomplete', function (e) {
1047
1053
1048 var BACKSPACE = 8;
1054 var BACKSPACE = 8;
1049 var el = $(e.currentTarget);
1055 var el = $(e.currentTarget);
1050 if(e.which === BACKSPACE){
1056 if(e.which === BACKSPACE){
1051 var inputVal = el.val();
1057 var inputVal = el.val();
1052 if (inputVal === ""){
1058 if (inputVal === ""){
1053 removeGoToFilter()
1059 removeGoToFilter()
1054 }
1060 }
1055 }
1061 }
1056 });
1062 });
1057
1063
1058 </script>
1064 </script>
1059 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1065 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1060 </%def>
1066 </%def>
1061
1067
1062 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1068 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1063 <div class="modal-dialog">
1069 <div class="modal-dialog">
1064 <div class="modal-content">
1070 <div class="modal-content">
1065 <div class="modal-header">
1071 <div class="modal-header">
1066 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1072 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1067 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1073 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1068 </div>
1074 </div>
1069 <div class="modal-body">
1075 <div class="modal-body">
1070 <div class="block-left">
1076 <div class="block-left">
1071 <table class="keyboard-mappings">
1077 <table class="keyboard-mappings">
1072 <tbody>
1078 <tbody>
1073 <tr>
1079 <tr>
1074 <th></th>
1080 <th></th>
1075 <th>${_('Site-wide shortcuts')}</th>
1081 <th>${_('Site-wide shortcuts')}</th>
1076 </tr>
1082 </tr>
1077 <%
1083 <%
1078 elems = [
1084 elems = [
1079 ('/', 'Use quick search box'),
1085 ('/', 'Use quick search box'),
1080 ('g h', 'Goto home page'),
1086 ('g h', 'Goto home page'),
1081 ('g g', 'Goto my private gists page'),
1087 ('g g', 'Goto my private gists page'),
1082 ('g G', 'Goto my public gists page'),
1088 ('g G', 'Goto my public gists page'),
1083 ('g 0-9', 'Goto bookmarked items from 0-9'),
1089 ('g 0-9', 'Goto bookmarked items from 0-9'),
1084 ('n r', 'New repository page'),
1090 ('n r', 'New repository page'),
1085 ('n g', 'New gist page'),
1091 ('n g', 'New gist page'),
1086 ]
1092 ]
1087 %>
1093 %>
1088 %for key, desc in elems:
1094 %for key, desc in elems:
1089 <tr>
1095 <tr>
1090 <td class="keys">
1096 <td class="keys">
1091 <span class="key tag">${key}</span>
1097 <span class="key tag">${key}</span>
1092 </td>
1098 </td>
1093 <td>${desc}</td>
1099 <td>${desc}</td>
1094 </tr>
1100 </tr>
1095 %endfor
1101 %endfor
1096 </tbody>
1102 </tbody>
1097 </table>
1103 </table>
1098 </div>
1104 </div>
1099 <div class="block-left">
1105 <div class="block-left">
1100 <table class="keyboard-mappings">
1106 <table class="keyboard-mappings">
1101 <tbody>
1107 <tbody>
1102 <tr>
1108 <tr>
1103 <th></th>
1109 <th></th>
1104 <th>${_('Repositories')}</th>
1110 <th>${_('Repositories')}</th>
1105 </tr>
1111 </tr>
1106 <%
1112 <%
1107 elems = [
1113 elems = [
1108 ('g s', 'Goto summary page'),
1114 ('g s', 'Goto summary page'),
1109 ('g c', 'Goto changelog page'),
1115 ('g c', 'Goto changelog page'),
1110 ('g f', 'Goto files page'),
1116 ('g f', 'Goto files page'),
1111 ('g F', 'Goto files page with file search activated'),
1117 ('g F', 'Goto files page with file search activated'),
1112 ('g p', 'Goto pull requests page'),
1118 ('g p', 'Goto pull requests page'),
1113 ('g o', 'Goto repository settings'),
1119 ('g o', 'Goto repository settings'),
1114 ('g O', 'Goto repository access permissions settings'),
1120 ('g O', 'Goto repository access permissions settings'),
1115 ]
1121 ]
1116 %>
1122 %>
1117 %for key, desc in elems:
1123 %for key, desc in elems:
1118 <tr>
1124 <tr>
1119 <td class="keys">
1125 <td class="keys">
1120 <span class="key tag">${key}</span>
1126 <span class="key tag">${key}</span>
1121 </td>
1127 </td>
1122 <td>${desc}</td>
1128 <td>${desc}</td>
1123 </tr>
1129 </tr>
1124 %endfor
1130 %endfor
1125 </tbody>
1131 </tbody>
1126 </table>
1132 </table>
1127 </div>
1133 </div>
1128 </div>
1134 </div>
1129 <div class="modal-footer">
1135 <div class="modal-footer">
1130 </div>
1136 </div>
1131 </div><!-- /.modal-content -->
1137 </div><!-- /.modal-content -->
1132 </div><!-- /.modal-dialog -->
1138 </div><!-- /.modal-dialog -->
1133 </div><!-- /.modal -->
1139 </div><!-- /.modal -->
General Comments 0
You need to be logged in to leave comments. Login now