##// END OF EJS Templates
quick-search: improve styling of search input and results.
dan -
r3443:6236d000 default
parent child Browse files
Show More
@@ -1,63 +1,69 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
21
22 def assert_and_get_main_filter_content(result):
22 def assert_and_get_main_filter_content(result):
23 repos = []
23 repos = []
24 groups = []
24 groups = []
25 commits = []
25 commits = []
26 users = []
26 users = []
27 for data_item in result:
27 for data_item in result:
28 assert data_item['id']
28 assert data_item['id']
29 assert data_item['value']
29 assert data_item['value']
30 assert data_item['value_display']
30 assert data_item['value_display']
31 assert data_item['url']
31 assert data_item['url']
32
32
33 if data_item['type'] == 'search':
33 if data_item['type'] == 'search':
34 display_val = data_item['value_display']
34 display_val = data_item['value_display']
35 assert 'Search for:' in display_val, display_val
35 if data_item['id'] == -1:
36 assert 'File search for:' in display_val, display_val
37 elif data_item['id'] == -2:
38 assert 'Commit search for:' in display_val, display_val
39 else:
40 assert False, 'No Proper ID returned {}'.format(data_item['id'])
41
36 elif data_item['type'] == 'repo':
42 elif data_item['type'] == 'repo':
37 repos.append(data_item)
43 repos.append(data_item)
38 elif data_item['type'] == 'repo_group':
44 elif data_item['type'] == 'repo_group':
39 groups.append(data_item)
45 groups.append(data_item)
40 elif data_item['type'] == 'user':
46 elif data_item['type'] == 'user':
41 users.append(data_item)
47 users.append(data_item)
42 elif data_item['type'] == 'commit':
48 elif data_item['type'] == 'commit':
43 commits.append(data_item)
49 commits.append(data_item)
44 else:
50 else:
45 raise Exception('invalid type `%s`' % data_item['type'])
51 raise Exception('invalid type `%s`' % data_item['type'])
46
52
47 return repos, groups, users, commits
53 return repos, groups, users, commits
48
54
49
55
50 def assert_and_get_repo_list_content(result):
56 def assert_and_get_repo_list_content(result):
51 repos = []
57 repos = []
52 for data in result:
58 for data in result:
53 for data_item in data['children']:
59 for data_item in data['children']:
54 assert data_item['id']
60 assert data_item['id']
55 assert data_item['text']
61 assert data_item['text']
56 assert data_item['url']
62 assert data_item['url']
57
63
58 if data_item['type'] == 'repo':
64 if data_item['type'] == 'repo':
59 repos.append(data_item)
65 repos.append(data_item)
60 else:
66 else:
61 raise Exception('invalid type %s' % data_item['type'])
67 raise Exception('invalid type %s' % data_item['type'])
62
68
63 return repos
69 return repos
@@ -1,596 +1,607 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,
30 LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator,
31 CSRFRequired)
31 CSRFRequired)
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.model.db import (
35 from rhodecode.model.db import (
36 func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
36 func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo_group import RepoGroupModel
38 from rhodecode.model.repo_group import RepoGroupModel
39 from rhodecode.model.scm import RepoGroupList, RepoList
39 from rhodecode.model.scm import RepoGroupList, RepoList
40 from rhodecode.model.user import UserModel
40 from rhodecode.model.user import UserModel
41 from rhodecode.model.user_group import UserGroupModel
41 from rhodecode.model.user_group import UserGroupModel
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class HomeView(BaseAppView):
46 class HomeView(BaseAppView):
47
47
48 def load_default_context(self):
48 def load_default_context(self):
49 c = self._get_local_tmpl_context()
49 c = self._get_local_tmpl_context()
50 c.user = c.auth_user.get_instance()
50 c.user = c.auth_user.get_instance()
51
51
52 return c
52 return c
53
53
54 @LoginRequired()
54 @LoginRequired()
55 @view_config(
55 @view_config(
56 route_name='user_autocomplete_data', request_method='GET',
56 route_name='user_autocomplete_data', request_method='GET',
57 renderer='json_ext', xhr=True)
57 renderer='json_ext', xhr=True)
58 def user_autocomplete_data(self):
58 def user_autocomplete_data(self):
59 self.load_default_context()
59 self.load_default_context()
60 query = self.request.GET.get('query')
60 query = self.request.GET.get('query')
61 active = str2bool(self.request.GET.get('active') or True)
61 active = str2bool(self.request.GET.get('active') or True)
62 include_groups = str2bool(self.request.GET.get('user_groups'))
62 include_groups = str2bool(self.request.GET.get('user_groups'))
63 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
63 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
64 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
64 skip_default_user = str2bool(self.request.GET.get('skip_default_user'))
65
65
66 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
66 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
67 query, active, include_groups)
67 query, active, include_groups)
68
68
69 _users = UserModel().get_users(
69 _users = UserModel().get_users(
70 name_contains=query, only_active=active)
70 name_contains=query, only_active=active)
71
71
72 def maybe_skip_default_user(usr):
72 def maybe_skip_default_user(usr):
73 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
73 if skip_default_user and usr['username'] == UserModel.cls.DEFAULT_USER:
74 return False
74 return False
75 return True
75 return True
76 _users = filter(maybe_skip_default_user, _users)
76 _users = filter(maybe_skip_default_user, _users)
77
77
78 if include_groups:
78 if include_groups:
79 # extend with user groups
79 # extend with user groups
80 _user_groups = UserGroupModel().get_user_groups(
80 _user_groups = UserGroupModel().get_user_groups(
81 name_contains=query, only_active=active,
81 name_contains=query, only_active=active,
82 expand_groups=expand_groups)
82 expand_groups=expand_groups)
83 _users = _users + _user_groups
83 _users = _users + _user_groups
84
84
85 return {'suggestions': _users}
85 return {'suggestions': _users}
86
86
87 @LoginRequired()
87 @LoginRequired()
88 @NotAnonymous()
88 @NotAnonymous()
89 @view_config(
89 @view_config(
90 route_name='user_group_autocomplete_data', request_method='GET',
90 route_name='user_group_autocomplete_data', request_method='GET',
91 renderer='json_ext', xhr=True)
91 renderer='json_ext', xhr=True)
92 def user_group_autocomplete_data(self):
92 def user_group_autocomplete_data(self):
93 self.load_default_context()
93 self.load_default_context()
94 query = self.request.GET.get('query')
94 query = self.request.GET.get('query')
95 active = str2bool(self.request.GET.get('active') or True)
95 active = str2bool(self.request.GET.get('active') or True)
96 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
96 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
97
97
98 log.debug('generating user group list, query:%s, active:%s',
98 log.debug('generating user group list, query:%s, active:%s',
99 query, active)
99 query, active)
100
100
101 _user_groups = UserGroupModel().get_user_groups(
101 _user_groups = UserGroupModel().get_user_groups(
102 name_contains=query, only_active=active,
102 name_contains=query, only_active=active,
103 expand_groups=expand_groups)
103 expand_groups=expand_groups)
104 _user_groups = _user_groups
104 _user_groups = _user_groups
105
105
106 return {'suggestions': _user_groups}
106 return {'suggestions': _user_groups}
107
107
108 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
108 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
109 org_query = name_contains
109 org_query = name_contains
110 allowed_ids = self._rhodecode_user.repo_acl_ids(
110 allowed_ids = self._rhodecode_user.repo_acl_ids(
111 ['repository.read', 'repository.write', 'repository.admin'],
111 ['repository.read', 'repository.write', 'repository.admin'],
112 cache=False, name_filter=name_contains) or [-1]
112 cache=False, name_filter=name_contains) or [-1]
113
113
114 query = Repository.query()\
114 query = Repository.query()\
115 .order_by(func.length(Repository.repo_name))\
115 .order_by(func.length(Repository.repo_name))\
116 .order_by(Repository.repo_name)\
116 .order_by(Repository.repo_name)\
117 .filter(Repository.archived.isnot(true()))\
117 .filter(Repository.archived.isnot(true()))\
118 .filter(or_(
118 .filter(or_(
119 # generate multiple IN to fix limitation problems
119 # generate multiple IN to fix limitation problems
120 *in_filter_generator(Repository.repo_id, allowed_ids)
120 *in_filter_generator(Repository.repo_id, allowed_ids)
121 ))
121 ))
122
122
123 if repo_type:
123 if repo_type:
124 query = query.filter(Repository.repo_type == repo_type)
124 query = query.filter(Repository.repo_type == repo_type)
125
125
126 if name_contains:
126 if name_contains:
127 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
127 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
128 query = query.filter(
128 query = query.filter(
129 Repository.repo_name.ilike(ilike_expression))
129 Repository.repo_name.ilike(ilike_expression))
130 query = query.limit(limit)
130 query = query.limit(limit)
131
131
132 acl_iter = query
132 acl_iter = query
133
133
134 return [
134 return [
135 {
135 {
136 'id': obj.repo_name,
136 'id': obj.repo_name,
137 'value': org_query,
137 'value': org_query,
138 'value_display': obj.repo_name,
138 'value_display': obj.repo_name,
139 'text': obj.repo_name,
139 'text': obj.repo_name,
140 'type': 'repo',
140 'type': 'repo',
141 'repo_id': obj.repo_id,
141 'repo_id': obj.repo_id,
142 'repo_type': obj.repo_type,
142 'repo_type': obj.repo_type,
143 'private': obj.private,
143 'private': obj.private,
144 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
144 'url': h.route_path('repo_summary', repo_name=obj.repo_name)
145 }
145 }
146 for obj in acl_iter]
146 for obj in acl_iter]
147
147
148 def _get_repo_group_list(self, name_contains=None, limit=20):
148 def _get_repo_group_list(self, name_contains=None, limit=20):
149 org_query = name_contains
149 org_query = name_contains
150 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
150 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
151 ['group.read', 'group.write', 'group.admin'],
151 ['group.read', 'group.write', 'group.admin'],
152 cache=False, name_filter=name_contains) or [-1]
152 cache=False, name_filter=name_contains) or [-1]
153
153
154 query = RepoGroup.query()\
154 query = RepoGroup.query()\
155 .order_by(func.length(RepoGroup.group_name))\
155 .order_by(func.length(RepoGroup.group_name))\
156 .order_by(RepoGroup.group_name) \
156 .order_by(RepoGroup.group_name) \
157 .filter(or_(
157 .filter(or_(
158 # generate multiple IN to fix limitation problems
158 # generate multiple IN to fix limitation problems
159 *in_filter_generator(RepoGroup.group_id, allowed_ids)
159 *in_filter_generator(RepoGroup.group_id, allowed_ids)
160 ))
160 ))
161
161
162 if name_contains:
162 if name_contains:
163 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
163 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
164 query = query.filter(
164 query = query.filter(
165 RepoGroup.group_name.ilike(ilike_expression))
165 RepoGroup.group_name.ilike(ilike_expression))
166 query = query.limit(limit)
166 query = query.limit(limit)
167
167
168 acl_iter = query
168 acl_iter = query
169
169
170 return [
170 return [
171 {
171 {
172 'id': obj.group_name,
172 'id': obj.group_name,
173 'value': org_query,
173 'value': org_query,
174 'value_display': obj.group_name,
174 'value_display': obj.group_name,
175 'text': obj.group_name,
175 'text': obj.group_name,
176 'type': 'repo_group',
176 'type': 'repo_group',
177 'repo_group_id': obj.group_id,
177 'repo_group_id': obj.group_id,
178 'url': h.route_path(
178 'url': h.route_path(
179 'repo_group_home', repo_group_name=obj.group_name)
179 'repo_group_home', repo_group_name=obj.group_name)
180 }
180 }
181 for obj in acl_iter]
181 for obj in acl_iter]
182
182
183 def _get_user_list(self, name_contains=None, limit=20):
183 def _get_user_list(self, name_contains=None, limit=20):
184 org_query = name_contains
184 org_query = name_contains
185 if not name_contains:
185 if not name_contains:
186 return []
186 return []
187
187
188 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
188 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
189 if len(name_contains) != 1:
189 if len(name_contains) != 1:
190 return []
190 return []
191 name_contains = name_contains[0]
191 name_contains = name_contains[0]
192
192
193 query = User.query()\
193 query = User.query()\
194 .order_by(func.length(User.username))\
194 .order_by(func.length(User.username))\
195 .order_by(User.username) \
195 .order_by(User.username) \
196 .filter(User.username != User.DEFAULT_USER)
196 .filter(User.username != User.DEFAULT_USER)
197
197
198 if name_contains:
198 if name_contains:
199 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
199 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
200 query = query.filter(
200 query = query.filter(
201 User.username.ilike(ilike_expression))
201 User.username.ilike(ilike_expression))
202 query = query.limit(limit)
202 query = query.limit(limit)
203
203
204 acl_iter = query
204 acl_iter = query
205
205
206 return [
206 return [
207 {
207 {
208 'id': obj.user_id,
208 'id': obj.user_id,
209 'value': org_query,
209 'value': org_query,
210 'value_display': obj.username,
210 'value_display': obj.username,
211 'type': 'user',
211 'type': 'user',
212 'icon_link': h.gravatar_url(obj.email, 30),
212 'icon_link': h.gravatar_url(obj.email, 30),
213 'url': h.route_path(
213 'url': h.route_path(
214 'user_profile', username=obj.username)
214 'user_profile', username=obj.username)
215 }
215 }
216 for obj in acl_iter]
216 for obj in acl_iter]
217
217
218 def _get_user_groups_list(self, name_contains=None, limit=20):
218 def _get_user_groups_list(self, name_contains=None, limit=20):
219 org_query = name_contains
219 org_query = name_contains
220 if not name_contains:
220 if not name_contains:
221 return []
221 return []
222
222
223 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
223 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
224 if len(name_contains) != 1:
224 if len(name_contains) != 1:
225 return []
225 return []
226 name_contains = name_contains[0]
226 name_contains = name_contains[0]
227
227
228 query = UserGroup.query()\
228 query = UserGroup.query()\
229 .order_by(func.length(UserGroup.users_group_name))\
229 .order_by(func.length(UserGroup.users_group_name))\
230 .order_by(UserGroup.users_group_name)
230 .order_by(UserGroup.users_group_name)
231
231
232 if name_contains:
232 if name_contains:
233 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
233 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
234 query = query.filter(
234 query = query.filter(
235 UserGroup.users_group_name.ilike(ilike_expression))
235 UserGroup.users_group_name.ilike(ilike_expression))
236 query = query.limit(limit)
236 query = query.limit(limit)
237
237
238 acl_iter = query
238 acl_iter = query
239
239
240 return [
240 return [
241 {
241 {
242 'id': obj.users_group_id,
242 'id': obj.users_group_id,
243 'value': org_query,
243 'value': org_query,
244 'value_display': obj.users_group_name,
244 'value_display': obj.users_group_name,
245 'type': 'user_group',
245 'type': 'user_group',
246 'url': h.route_path(
246 'url': h.route_path(
247 'user_group_profile', user_group_name=obj.users_group_name)
247 'user_group_profile', user_group_name=obj.users_group_name)
248 }
248 }
249 for obj in acl_iter]
249 for obj in acl_iter]
250
250
251 def _get_hash_commit_list(self, auth_user, searcher, query):
251 def _get_hash_commit_list(self, auth_user, searcher, query):
252 org_query = query
252 org_query = query
253 if not query or len(query) < 3 or not searcher:
253 if not query or len(query) < 3 or not searcher:
254 return []
254 return []
255
255
256 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
256 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
257
257
258 if len(commit_hashes) != 1:
258 if len(commit_hashes) != 1:
259 return []
259 return []
260 commit_hash = commit_hashes[0]
260 commit_hash = commit_hashes[0]
261
261
262 result = searcher.search(
262 result = searcher.search(
263 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
263 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
264 raise_on_exc=False)
264 raise_on_exc=False)
265
265
266 return [
266 commits = []
267 {
267 for entry in result['results']:
268 repo_data = {
269 'repository_id': entry.get('repository_id'),
270 'repository_type': entry.get('repo_type'),
271 'repository_name': entry.get('repository'),
272 }
273
274 commit_entry = {
268 'id': entry['commit_id'],
275 'id': entry['commit_id'],
269 'value': org_query,
276 'value': org_query,
270 'value_display': 'repo `{}` commit: {}'.format(
277 'value_display': '`{}` commit: {}'.format(
271 entry['repository'], entry['commit_id']),
278 entry['repository'], entry['commit_id']),
272 'type': 'commit',
279 'type': 'commit',
273 'repo': entry['repository'],
280 'repo': entry['repository'],
281 'repo_data': repo_data,
282
274 'url': h.route_path(
283 'url': h.route_path(
275 'repo_commit',
284 'repo_commit',
276 repo_name=entry['repository'], commit_id=entry['commit_id'])
285 repo_name=entry['repository'], commit_id=entry['commit_id'])
277 }
286 }
278 for entry in result['results']]
287
288 commits.append(commit_entry)
289 return commits
279
290
280 @LoginRequired()
291 @LoginRequired()
281 @view_config(
292 @view_config(
282 route_name='repo_list_data', request_method='GET',
293 route_name='repo_list_data', request_method='GET',
283 renderer='json_ext', xhr=True)
294 renderer='json_ext', xhr=True)
284 def repo_list_data(self):
295 def repo_list_data(self):
285 _ = self.request.translate
296 _ = self.request.translate
286 self.load_default_context()
297 self.load_default_context()
287
298
288 query = self.request.GET.get('query')
299 query = self.request.GET.get('query')
289 repo_type = self.request.GET.get('repo_type')
300 repo_type = self.request.GET.get('repo_type')
290 log.debug('generating repo list, query:%s, repo_type:%s',
301 log.debug('generating repo list, query:%s, repo_type:%s',
291 query, repo_type)
302 query, repo_type)
292
303
293 res = []
304 res = []
294 repos = self._get_repo_list(query, repo_type=repo_type)
305 repos = self._get_repo_list(query, repo_type=repo_type)
295 if repos:
306 if repos:
296 res.append({
307 res.append({
297 'text': _('Repositories'),
308 'text': _('Repositories'),
298 'children': repos
309 'children': repos
299 })
310 })
300
311
301 data = {
312 data = {
302 'more': False,
313 'more': False,
303 'results': res
314 'results': res
304 }
315 }
305 return data
316 return data
306
317
307 @LoginRequired()
318 @LoginRequired()
308 @view_config(
319 @view_config(
309 route_name='repo_group_list_data', request_method='GET',
320 route_name='repo_group_list_data', request_method='GET',
310 renderer='json_ext', xhr=True)
321 renderer='json_ext', xhr=True)
311 def repo_group_list_data(self):
322 def repo_group_list_data(self):
312 _ = self.request.translate
323 _ = self.request.translate
313 self.load_default_context()
324 self.load_default_context()
314
325
315 query = self.request.GET.get('query')
326 query = self.request.GET.get('query')
316
327
317 log.debug('generating repo group list, query:%s',
328 log.debug('generating repo group list, query:%s',
318 query)
329 query)
319
330
320 res = []
331 res = []
321 repo_groups = self._get_repo_group_list(query)
332 repo_groups = self._get_repo_group_list(query)
322 if repo_groups:
333 if repo_groups:
323 res.append({
334 res.append({
324 'text': _('Repository Groups'),
335 'text': _('Repository Groups'),
325 'children': repo_groups
336 'children': repo_groups
326 })
337 })
327
338
328 data = {
339 data = {
329 'more': False,
340 'more': False,
330 'results': res
341 'results': res
331 }
342 }
332 return data
343 return data
333
344
334 def _get_default_search_queries(self, search_context, searcher, query):
345 def _get_default_search_queries(self, search_context, searcher, query):
335 if not searcher:
346 if not searcher:
336 return []
347 return []
337
348
338 is_es_6 = searcher.is_es_6
349 is_es_6 = searcher.is_es_6
339
350
340 queries = []
351 queries = []
341 repo_group_name, repo_name, repo_context = None, None, None
352 repo_group_name, repo_name, repo_context = None, None, None
342
353
343 # repo group context
354 # repo group context
344 if search_context.get('search_context[repo_group_name]'):
355 if search_context.get('search_context[repo_group_name]'):
345 repo_group_name = search_context.get('search_context[repo_group_name]')
356 repo_group_name = search_context.get('search_context[repo_group_name]')
346 if search_context.get('search_context[repo_name]'):
357 if search_context.get('search_context[repo_name]'):
347 repo_name = search_context.get('search_context[repo_name]')
358 repo_name = search_context.get('search_context[repo_name]')
348 repo_context = search_context.get('search_context[repo_view_type]')
359 repo_context = search_context.get('search_context[repo_view_type]')
349
360
350 if is_es_6 and repo_name:
361 if is_es_6 and repo_name:
351 # files
362 # files
352 def query_modifier():
363 def query_modifier():
353 qry = query
364 qry = query
354 return {'q': qry, 'type': 'content'}
365 return {'q': qry, 'type': 'content'}
355 label = u'File search for `{}` in this repository.'.format(query)
366 label = u'File search for `{}` in this repository.'.format(query)
356 queries.append(
367 queries.append(
357 {
368 {
358 'id': -10,
369 'id': -10,
359 'value': query,
370 'value': query,
360 'value_display': label,
371 'value_display': label,
361 'type': 'search',
372 'type': 'search',
362 'url': h.route_path('search_repo',
373 'url': h.route_path('search_repo',
363 repo_name=repo_name,
374 repo_name=repo_name,
364 _query=query_modifier())
375 _query=query_modifier())
365 }
376 }
366 )
377 )
367
378
368 # commits
379 # commits
369 def query_modifier():
380 def query_modifier():
370 qry = query
381 qry = query
371 return {'q': qry, 'type': 'commit'}
382 return {'q': qry, 'type': 'commit'}
372
383
373 label = u'Commit search for `{}` in this repository.'.format(query)
384 label = u'Commit search for `{}` in this repository.'.format(query)
374 queries.append(
385 queries.append(
375 {
386 {
376 'id': -10,
387 'id': -20,
377 'value': query,
388 'value': query,
378 'value_display': label,
389 'value_display': label,
379 'type': 'search',
390 'type': 'search',
380 'url': h.route_path('search_repo',
391 'url': h.route_path('search_repo',
381 repo_name=repo_name,
392 repo_name=repo_name,
382 _query=query_modifier())
393 _query=query_modifier())
383 }
394 }
384 )
395 )
385
396
386 elif is_es_6 and repo_group_name:
397 elif is_es_6 and repo_group_name:
387 # files
398 # files
388 def query_modifier():
399 def query_modifier():
389 qry = query
400 qry = query
390 return {'q': qry, 'type': 'content'}
401 return {'q': qry, 'type': 'content'}
391
402
392 label = u'File search for `{}` in this repository group'.format(query)
403 label = u'File search for `{}` in this repository group'.format(query)
393 queries.append(
404 queries.append(
394 {
405 {
395 'id': -20,
406 'id': -30,
396 'value': query,
407 'value': query,
397 'value_display': label,
408 'value_display': label,
398 'type': 'search',
409 'type': 'search',
399 'url': h.route_path('search_repo_group',
410 'url': h.route_path('search_repo_group',
400 repo_group_name=repo_group_name,
411 repo_group_name=repo_group_name,
401 _query=query_modifier())
412 _query=query_modifier())
402 }
413 }
403 )
414 )
404
415
405 # commits
416 # commits
406 def query_modifier():
417 def query_modifier():
407 qry = query
418 qry = query
408 return {'q': qry, 'type': 'commit'}
419 return {'q': qry, 'type': 'commit'}
409
420
410 label = u'Commit search for `{}` in this repository group'.format(query)
421 label = u'Commit search for `{}` in this repository group'.format(query)
411 queries.append(
422 queries.append(
412 {
423 {
413 'id': -20,
424 'id': -40,
414 'value': query,
425 'value': query,
415 'value_display': label,
426 'value_display': label,
416 'type': 'search',
427 'type': 'search',
417 'url': h.route_path('search_repo_group',
428 'url': h.route_path('search_repo_group',
418 repo_group_name=repo_group_name,
429 repo_group_name=repo_group_name,
419 _query=query_modifier())
430 _query=query_modifier())
420 }
431 }
421 )
432 )
422
433
423 if not queries:
434 if not queries:
424 queries.append(
435 queries.append(
425 {
436 {
426 'id': -1,
437 'id': -1,
427 'value': query,
438 'value': query,
428 'value_display': u'Commit search for: `{}`'.format(query),
439 'value_display': u'File search for: `{}`'.format(query),
429 'type': 'search',
440 'type': 'search',
430 'url': h.route_path('search',
441 'url': h.route_path('search',
431 _query={'q': query, 'type': 'content'})
442 _query={'q': query, 'type': 'content'})
432 })
443 })
433 queries.append(
444 queries.append(
434 {
445 {
435 'id': -1,
446 'id': -2,
436 'value': query,
447 'value': query,
437 'value_display': u'File search for: `{}`'.format(query),
448 'value_display': u'Commit search for: `{}`'.format(query),
438 'type': 'search',
449 'type': 'search',
439 'url': h.route_path('search',
450 'url': h.route_path('search',
440 _query={'q': query, 'type': 'commit'})
451 _query={'q': query, 'type': 'commit'})
441 })
452 })
442
453
443 return queries
454 return queries
444
455
445 @LoginRequired()
456 @LoginRequired()
446 @view_config(
457 @view_config(
447 route_name='goto_switcher_data', request_method='GET',
458 route_name='goto_switcher_data', request_method='GET',
448 renderer='json_ext', xhr=True)
459 renderer='json_ext', xhr=True)
449 def goto_switcher_data(self):
460 def goto_switcher_data(self):
450 c = self.load_default_context()
461 c = self.load_default_context()
451
462
452 _ = self.request.translate
463 _ = self.request.translate
453
464
454 query = self.request.GET.get('query')
465 query = self.request.GET.get('query')
455 log.debug('generating main filter data, query %s', query)
466 log.debug('generating main filter data, query %s', query)
456
467
457 res = []
468 res = []
458 if not query:
469 if not query:
459 return {'suggestions': res}
470 return {'suggestions': res}
460
471
461 searcher = searcher_from_config(self.request.registry.settings)
472 searcher = searcher_from_config(self.request.registry.settings)
462 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
473 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
463 res.append(_q)
474 res.append(_q)
464
475
465 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
476 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
466 if repo_group_id:
477 if repo_group_id:
467 repo_group = RepoGroup.get(repo_group_id)
478 repo_group = RepoGroup.get(repo_group_id)
468 composed_hint = '{}/{}'.format(repo_group.group_name, query)
479 composed_hint = '{}/{}'.format(repo_group.group_name, query)
469 show_hint = not query.startswith(repo_group.group_name)
480 show_hint = not query.startswith(repo_group.group_name)
470 if repo_group and show_hint:
481 if repo_group and show_hint:
471 hint = u'Repository search inside: `{}`'.format(composed_hint)
482 hint = u'Repository search inside: `{}`'.format(composed_hint)
472 res.append({
483 res.append({
473 'id': -1,
484 'id': -1,
474 'value': composed_hint,
485 'value': composed_hint,
475 'value_display': hint,
486 'value_display': hint,
476 'type': 'hint',
487 'type': 'hint',
477 'url': ""
488 'url': ""
478 })
489 })
479
490
480 repo_groups = self._get_repo_group_list(query)
491 repo_groups = self._get_repo_group_list(query)
481 for serialized_repo_group in repo_groups:
492 for serialized_repo_group in repo_groups:
482 res.append(serialized_repo_group)
493 res.append(serialized_repo_group)
483
494
484 repos = self._get_repo_list(query)
495 repos = self._get_repo_list(query)
485 for serialized_repo in repos:
496 for serialized_repo in repos:
486 res.append(serialized_repo)
497 res.append(serialized_repo)
487
498
488 # TODO(marcink): should all logged in users be allowed to search others?
499 # TODO(marcink): should all logged in users be allowed to search others?
489 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
500 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
490 if allowed_user_search:
501 if allowed_user_search:
491 users = self._get_user_list(query)
502 users = self._get_user_list(query)
492 for serialized_user in users:
503 for serialized_user in users:
493 res.append(serialized_user)
504 res.append(serialized_user)
494
505
495 user_groups = self._get_user_groups_list(query)
506 user_groups = self._get_user_groups_list(query)
496 for serialized_user_group in user_groups:
507 for serialized_user_group in user_groups:
497 res.append(serialized_user_group)
508 res.append(serialized_user_group)
498
509
499 commits = self._get_hash_commit_list(c.auth_user, searcher, query)
510 commits = self._get_hash_commit_list(c.auth_user, searcher, query)
500 if commits:
511 if commits:
501 unique_repos = collections.OrderedDict()
512 unique_repos = collections.OrderedDict()
502 for commit in commits:
513 for commit in commits:
503 repo_name = commit['repo']
514 repo_name = commit['repo']
504 unique_repos.setdefault(repo_name, []).append(commit)
515 unique_repos.setdefault(repo_name, []).append(commit)
505
516
506 for repo, commits in unique_repos.items():
517 for repo, commits in unique_repos.items():
507 for commit in commits:
518 for commit in commits:
508 res.append(commit)
519 res.append(commit)
509
520
510 return {'suggestions': res}
521 return {'suggestions': res}
511
522
512 def _get_groups_and_repos(self, repo_group_id=None):
523 def _get_groups_and_repos(self, repo_group_id=None):
513 # repo groups groups
524 # repo groups groups
514 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
525 repo_group_list = RepoGroup.get_all_repo_groups(group_id=repo_group_id)
515 _perms = ['group.read', 'group.write', 'group.admin']
526 _perms = ['group.read', 'group.write', 'group.admin']
516 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
527 repo_group_list_acl = RepoGroupList(repo_group_list, perm_set=_perms)
517 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
528 repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
518 repo_group_list=repo_group_list_acl, admin=False)
529 repo_group_list=repo_group_list_acl, admin=False)
519
530
520 # repositories
531 # repositories
521 repo_list = Repository.get_all_repos(group_id=repo_group_id)
532 repo_list = Repository.get_all_repos(group_id=repo_group_id)
522 _perms = ['repository.read', 'repository.write', 'repository.admin']
533 _perms = ['repository.read', 'repository.write', 'repository.admin']
523 repo_list_acl = RepoList(repo_list, perm_set=_perms)
534 repo_list_acl = RepoList(repo_list, perm_set=_perms)
524 repo_data = RepoModel().get_repos_as_dict(
535 repo_data = RepoModel().get_repos_as_dict(
525 repo_list=repo_list_acl, admin=False)
536 repo_list=repo_list_acl, admin=False)
526
537
527 return repo_data, repo_group_data
538 return repo_data, repo_group_data
528
539
529 @LoginRequired()
540 @LoginRequired()
530 @view_config(
541 @view_config(
531 route_name='home', request_method='GET',
542 route_name='home', request_method='GET',
532 renderer='rhodecode:templates/index.mako')
543 renderer='rhodecode:templates/index.mako')
533 def main_page(self):
544 def main_page(self):
534 c = self.load_default_context()
545 c = self.load_default_context()
535 c.repo_group = None
546 c.repo_group = None
536
547
537 repo_data, repo_group_data = self._get_groups_and_repos()
548 repo_data, repo_group_data = self._get_groups_and_repos()
538 # json used to render the grids
549 # json used to render the grids
539 c.repos_data = json.dumps(repo_data)
550 c.repos_data = json.dumps(repo_data)
540 c.repo_groups_data = json.dumps(repo_group_data)
551 c.repo_groups_data = json.dumps(repo_group_data)
541
552
542 return self._get_template_context(c)
553 return self._get_template_context(c)
543
554
544 @LoginRequired()
555 @LoginRequired()
545 @HasRepoGroupPermissionAnyDecorator(
556 @HasRepoGroupPermissionAnyDecorator(
546 'group.read', 'group.write', 'group.admin')
557 'group.read', 'group.write', 'group.admin')
547 @view_config(
558 @view_config(
548 route_name='repo_group_home', request_method='GET',
559 route_name='repo_group_home', request_method='GET',
549 renderer='rhodecode:templates/index_repo_group.mako')
560 renderer='rhodecode:templates/index_repo_group.mako')
550 @view_config(
561 @view_config(
551 route_name='repo_group_home_slash', request_method='GET',
562 route_name='repo_group_home_slash', request_method='GET',
552 renderer='rhodecode:templates/index_repo_group.mako')
563 renderer='rhodecode:templates/index_repo_group.mako')
553 def repo_group_main_page(self):
564 def repo_group_main_page(self):
554 c = self.load_default_context()
565 c = self.load_default_context()
555 c.repo_group = self.request.db_repo_group
566 c.repo_group = self.request.db_repo_group
556 repo_data, repo_group_data = self._get_groups_and_repos(
567 repo_data, repo_group_data = self._get_groups_and_repos(
557 c.repo_group.group_id)
568 c.repo_group.group_id)
558
569
559 # json used to render the grids
570 # json used to render the grids
560 c.repos_data = json.dumps(repo_data)
571 c.repos_data = json.dumps(repo_data)
561 c.repo_groups_data = json.dumps(repo_group_data)
572 c.repo_groups_data = json.dumps(repo_group_data)
562
573
563 return self._get_template_context(c)
574 return self._get_template_context(c)
564
575
565 @LoginRequired()
576 @LoginRequired()
566 @CSRFRequired()
577 @CSRFRequired()
567 @view_config(
578 @view_config(
568 route_name='markup_preview', request_method='POST',
579 route_name='markup_preview', request_method='POST',
569 renderer='string', xhr=True)
580 renderer='string', xhr=True)
570 def markup_preview(self):
581 def markup_preview(self):
571 # Technically a CSRF token is not needed as no state changes with this
582 # Technically a CSRF token is not needed as no state changes with this
572 # call. However, as this is a POST is better to have it, so automated
583 # call. However, as this is a POST is better to have it, so automated
573 # tools don't flag it as potential CSRF.
584 # tools don't flag it as potential CSRF.
574 # Post is required because the payload could be bigger than the maximum
585 # Post is required because the payload could be bigger than the maximum
575 # allowed by GET.
586 # allowed by GET.
576
587
577 text = self.request.POST.get('text')
588 text = self.request.POST.get('text')
578 renderer = self.request.POST.get('renderer') or 'rst'
589 renderer = self.request.POST.get('renderer') or 'rst'
579 if text:
590 if text:
580 return h.render(text, renderer=renderer, mentions=True)
591 return h.render(text, renderer=renderer, mentions=True)
581 return ''
592 return ''
582
593
583 @LoginRequired()
594 @LoginRequired()
584 @CSRFRequired()
595 @CSRFRequired()
585 @view_config(
596 @view_config(
586 route_name='store_user_session_value', request_method='POST',
597 route_name='store_user_session_value', request_method='POST',
587 renderer='string', xhr=True)
598 renderer='string', xhr=True)
588 def store_user_session_attr(self):
599 def store_user_session_attr(self):
589 key = self.request.POST.get('key')
600 key = self.request.POST.get('key')
590 val = self.request.POST.get('val')
601 val = self.request.POST.get('val')
591
602
592 existing_value = self.request.session.get(key)
603 existing_value = self.request.session.get(key)
593 if existing_value != val:
604 if existing_value != val:
594 self.request.session[key] = val
605 self.request.session[key] = val
595
606
596 return 'stored:{}'.format(key)
607 return 'stored:{}'.format(key)
@@ -1,684 +1,698 b''
1 // navigation.less
1 // navigation.less
2 // For use in RhodeCode applications;
2 // For use in RhodeCode applications;
3 // see style guide documentation for guidelines.
3 // see style guide documentation for guidelines.
4
4
5 // HEADER NAVIGATION
5 // HEADER NAVIGATION
6
6
7 .horizontal-list {
7 .horizontal-list {
8 float: right;
8 float: right;
9 display: block;
9 display: block;
10 margin: 0;
10 margin: 0;
11 padding: 0;
11 padding: 0;
12 -webkit-padding-start: 0;
12 -webkit-padding-start: 0;
13 text-align: left;
13 text-align: left;
14 font-size: @navigation-fontsize;
14 font-size: @navigation-fontsize;
15 color: @grey6;
15 color: @grey6;
16 z-index:10;
16 z-index:10;
17
17
18 li {
18 li {
19 line-height: 1em;
19 line-height: 1em;
20 list-style-type: none;
20 list-style-type: none;
21
21
22 a {
22 a {
23 padding: 0 .5em;
23 padding: 0 .5em;
24
24
25 &.menu_link_notifications {
25 &.menu_link_notifications {
26 .pill(7px,@rcblue);
26 .pill(7px,@rcblue);
27 display: inline;
27 display: inline;
28 margin: 0 7px 0 .7em;
28 margin: 0 7px 0 .7em;
29 font-size: @basefontsize;
29 font-size: @basefontsize;
30 color: white;
30 color: white;
31
31
32 &.empty {
32 &.empty {
33 background-color: @grey4;
33 background-color: @grey4;
34 }
34 }
35
35
36 &:hover {
36 &:hover {
37 background-color: @rcdarkblue;
37 background-color: @rcdarkblue;
38 }
38 }
39 }
39 }
40 }
40 }
41 .pill_container {
41 .pill_container {
42 margin: 1.25em 0px 0px 0px;
42 margin: 1.25em 0px 0px 0px;
43 float: right;
43 float: right;
44 }
44 }
45
45
46 &#quick_login_li {
46 &#quick_login_li {
47 &:hover {
47 &:hover {
48 color: @grey5;
48 color: @grey5;
49 }
49 }
50
50
51 a.menu_link_notifications {
51 a.menu_link_notifications {
52 color: white;
52 color: white;
53 }
53 }
54
54
55 .user {
55 .user {
56 padding-bottom: 10px;
56 padding-bottom: 10px;
57 }
57 }
58
58
59 &.open {
59 &.open {
60 .user {
60 .user {
61 border-bottom: 5px solid @rcblue;
61 border-bottom: 5px solid @rcblue;
62 }
62 }
63 }
63 }
64 }
64 }
65
65
66 &:before { content: none; }
66 &:before { content: none; }
67
67
68 &:last-child {
68 &:last-child {
69 .menulabel {
69 .menulabel {
70 padding-right: 0;
70 padding-right: 0;
71 border-right: none;
71 border-right: none;
72
72
73 .show_more {
73 .show_more {
74 padding-right: 0;
74 padding-right: 0;
75 }
75 }
76 }
76 }
77
77
78 &> a {
78 &> a {
79 border-bottom: none;
79 border-bottom: none;
80 }
80 }
81 }
81 }
82
82
83 &.active {
83 &.active {
84 border-bottom: 5px solid @rcblue;
84 border-bottom: 5px solid @rcblue;
85 }
85 }
86
86
87 &.open {
87 &.open {
88
88
89 a {
89 a {
90 color: white;
90 color: white;
91 }
91 }
92 }
92 }
93
93
94 &:focus {
94 &:focus {
95 outline: none;
95 outline: none;
96 }
96 }
97
97
98 ul li {
98 ul li {
99 display: block;
99 display: block;
100
100
101 &:last-child> a {
101 &:last-child> a {
102 border-bottom: none;
102 border-bottom: none;
103 }
103 }
104
104
105 ul li:last-child a {
105 ul li:last-child a {
106 /* we don't expect more then 3 levels of submenu and the third
106 /* we don't expect more then 3 levels of submenu and the third
107 level can have different html structure */
107 level can have different html structure */
108 border-bottom: none;
108 border-bottom: none;
109 }
109 }
110 }
110 }
111 }
111 }
112
112
113 > li {
113 > li {
114 float: left;
114 float: left;
115 display: block;
115 display: block;
116 padding: 0;
116 padding: 0;
117
117
118 > a,
118 > a,
119 &.has_select2 a {
119 &.has_select2 a {
120 display: block;
120 display: block;
121 padding: 10px 0 2px;
121 padding: 10px 0 2px;
122 }
122 }
123
123
124 .menulabel {
124 .menulabel {
125 padding: 0 .5em;
125 padding: 0 .5em;
126 line-height: 1em;
126 line-height: 1em;
127 // for this specifically we do not use a variable
127 // for this specifically we do not use a variable
128 border-right: 1px solid @grey4;
128 border-right: 1px solid @grey4;
129 }
129 }
130
130
131 .pr_notifications {
131 .pr_notifications {
132 padding-left: .5em;
132 padding-left: .5em;
133 }
133 }
134
134
135 .pr_notifications + .menulabel {
135 .pr_notifications + .menulabel {
136 display:inline;
136 display:inline;
137 padding-left: 0;
137 padding-left: 0;
138 }
138 }
139
139
140 &:hover,
140 &:hover,
141 &.open,
141 &.open,
142 &.active {
142 &.active {
143 a {
143 a {
144 color: @grey1;
144 color: @grey1;
145 }
145 }
146 }
146 }
147 }
147 }
148
148
149 pre {
149 pre {
150 margin: 0;
150 margin: 0;
151 padding: 0;
151 padding: 0;
152 }
152 }
153
153
154 .select2-container,
154 .select2-container,
155 .menulink.childs {
155 .menulink.childs {
156 position: relative;
156 position: relative;
157 }
157 }
158
158
159 #quick_login {
159 #quick_login {
160
160
161 li a {
161 li a {
162 padding: .5em 0;
162 padding: .5em 0;
163 border-bottom: none;
163 border-bottom: none;
164 color: @grey2;
164 color: @grey2;
165
165
166 &:hover { color: @grey1; }
166 &:hover { color: @grey1; }
167 }
167 }
168 }
168 }
169
169
170 #quick_login_link {
170 #quick_login_link {
171 display: inline-block;
171 display: inline-block;
172
172
173 .gravatar {
173 .gravatar {
174 border: 1px solid @grey5;
174 border: 1px solid @grey5;
175 }
175 }
176
176
177 .gravatar-login {
177 .gravatar-login {
178 height: 20px;
178 height: 20px;
179 width: 20px;
179 width: 20px;
180 margin: -8px 0;
180 margin: -8px 0;
181 padding: 0;
181 padding: 0;
182 }
182 }
183
183
184 &:hover .user {
184 &:hover .user {
185 color: @grey6;
185 color: @grey6;
186 }
186 }
187 }
187 }
188 }
188 }
189 .header .horizontal-list {
189 .header .horizontal-list {
190
190
191 li {
191 li {
192
192
193 &#quick_login_li {
193 &#quick_login_li {
194 padding-left: .5em;
194 padding-left: .5em;
195
195
196 &:hover #quick_login_link {
196 &:hover #quick_login_link {
197 color: inherit;
197 color: inherit;
198 }
198 }
199
199
200 .menu_link_user {
200 .menu_link_user {
201 padding: 0 2px;
201 padding: 0 2px;
202 }
202 }
203 }
203 }
204 list-style-type: none;
204 list-style-type: none;
205 }
205 }
206
206
207 > li {
207 > li {
208
208
209 a {
209 a {
210 padding: 18px 0 12px 0;
210 padding: 18px 0 12px 0;
211 color: @nav-grey;
211 color: @nav-grey;
212
212
213 &.menu_link_notifications {
213 &.menu_link_notifications {
214 padding: 1px 8px;
214 padding: 1px 8px;
215 }
215 }
216 }
216 }
217
217
218 &:hover,
218 &:hover,
219 &.open,
219 &.open,
220 &.active {
220 &.active {
221 .pill_container a {
221 .pill_container a {
222 // don't select text for the pill container, it has it' own
222 // don't select text for the pill container, it has it' own
223 // hover behaviour
223 // hover behaviour
224 color: @nav-grey;
224 color: @nav-grey;
225 }
225 }
226 }
226 }
227
227
228 &:hover,
228 &:hover,
229 &.open,
229 &.open,
230 &.active {
230 &.active {
231 a {
231 a {
232 color: @grey6;
232 color: @grey6;
233 }
233 }
234 }
234 }
235
235
236 .select2-dropdown-open a {
236 .select2-dropdown-open a {
237 color: @grey6;
237 color: @grey6;
238 }
238 }
239
239
240 .repo-switcher {
240 .repo-switcher {
241 padding-left: 0;
241 padding-left: 0;
242
242
243 .menulabel {
243 .menulabel {
244 padding-left: 0;
244 padding-left: 0;
245 }
245 }
246 }
246 }
247 }
247 }
248
248
249 li ul li {
249 li ul li {
250 background-color:@grey2;
250 background-color:@grey2;
251
251
252 a {
252 a {
253 padding: .5em 0;
253 padding: .5em 0;
254 border-bottom: @border-thickness solid @border-default-color;
254 border-bottom: @border-thickness solid @border-default-color;
255 color: @grey6;
255 color: @grey6;
256 }
256 }
257
257
258 &:last-child a, &.last a{
258 &:last-child a, &.last a{
259 border-bottom: none;
259 border-bottom: none;
260 }
260 }
261
261
262 &:hover {
262 &:hover {
263 background-color: @grey3;
263 background-color: @grey3;
264 }
264 }
265 }
265 }
266
266
267 .submenu {
267 .submenu {
268 margin-top: 5px;
268 margin-top: 5px;
269 }
269 }
270 }
270 }
271
271
272 // SUBMENUS
272 // SUBMENUS
273 .navigation .submenu {
273 .navigation .submenu {
274 display: none;
274 display: none;
275 }
275 }
276
276
277 .navigation li.open {
277 .navigation li.open {
278 .submenu {
278 .submenu {
279 display: block;
279 display: block;
280 }
280 }
281 }
281 }
282
282
283 .navigation li:last-child .submenu {
283 .navigation li:last-child .submenu {
284 right: -20px;
284 right: -20px;
285 left: auto;
285 left: auto;
286 }
286 }
287
287
288 .submenu {
288 .submenu {
289 position: absolute;
289 position: absolute;
290 top: 100%;
290 top: 100%;
291 left: 0;
291 left: 0;
292 min-width: 150px;
292 min-width: 150px;
293 margin: 6px 0 0;
293 margin: 6px 0 0;
294 padding: 0;
294 padding: 0;
295 text-align: left;
295 text-align: left;
296 font-family: @text-light;
296 font-family: @text-light;
297 border-radius: @border-radius;
297 border-radius: @border-radius;
298 z-index: 20;
298 z-index: 20;
299
299
300 li {
300 li {
301 display: block;
301 display: block;
302 margin: 0;
302 margin: 0;
303 padding: 0 .5em;
303 padding: 0 .5em;
304 line-height: 1em;
304 line-height: 1em;
305 color: @grey3;
305 color: @grey3;
306 background-color: @grey6;
306 background-color: @grey6;
307 list-style-type: none;
307 list-style-type: none;
308
308
309 a {
309 a {
310 display: block;
310 display: block;
311 width: 100%;
311 width: 100%;
312 padding: .5em 0;
312 padding: .5em 0;
313 border-right: none;
313 border-right: none;
314 border-bottom: @border-thickness solid white;
314 border-bottom: @border-thickness solid white;
315 color: @grey3;
315 color: @grey3;
316 }
316 }
317
317
318 ul {
318 ul {
319 display: none;
319 display: none;
320 position: absolute;
320 position: absolute;
321 top: 0;
321 top: 0;
322 right: 100%;
322 right: 100%;
323 padding: 0;
323 padding: 0;
324 z-index: 30;
324 z-index: 30;
325 }
325 }
326 &:hover {
326 &:hover {
327 background-color: @grey5;
327 background-color: @grey5;
328 -webkit-transition: background .3s;
328 -webkit-transition: background .3s;
329 -moz-transition: background .3s;
329 -moz-transition: background .3s;
330 -o-transition: background .3s;
330 -o-transition: background .3s;
331 transition: background .3s;
331 transition: background .3s;
332
332
333 ul {
333 ul {
334 display: block;
334 display: block;
335 }
335 }
336 }
336 }
337 }
337 }
338
338
339 }
339 }
340
340
341
341
342
342
343
343
344 // repo dropdown
344 // repo dropdown
345 .quick_repo_menu {
345 .quick_repo_menu {
346 width: 15px;
346 width: 15px;
347 text-align: center;
347 text-align: center;
348 position: relative;
348 position: relative;
349 cursor: pointer;
349 cursor: pointer;
350
350
351 div {
351 div {
352 overflow: visible !important;
352 overflow: visible !important;
353 }
353 }
354
354
355 &.sorting {
355 &.sorting {
356 cursor: auto;
356 cursor: auto;
357 }
357 }
358
358
359 &:hover {
359 &:hover {
360 .menu_items_container {
360 .menu_items_container {
361 position: absolute;
361 position: absolute;
362 display: block;
362 display: block;
363 }
363 }
364 .menu_items {
364 .menu_items {
365 display: block;
365 display: block;
366 }
366 }
367 }
367 }
368
368
369 i {
369 i {
370 margin: 0;
370 margin: 0;
371 color: @grey4;
371 color: @grey4;
372 }
372 }
373
373
374 .menu_items_container {
374 .menu_items_container {
375 position: absolute;
375 position: absolute;
376 top: 0;
376 top: 0;
377 left: 100%;
377 left: 100%;
378 margin: 0;
378 margin: 0;
379 padding: 0;
379 padding: 0;
380 list-style: none;
380 list-style: none;
381 background-color: @grey6;
381 background-color: @grey6;
382 z-index: 999;
382 z-index: 999;
383 text-align: left;
383 text-align: left;
384
384
385 a {
385 a {
386 color: @grey2;
386 color: @grey2;
387 }
387 }
388
388
389 ul.menu_items {
389 ul.menu_items {
390 margin: 0;
390 margin: 0;
391 padding: 0;
391 padding: 0;
392 }
392 }
393
393
394 li {
394 li {
395 margin: 0;
395 margin: 0;
396 padding: 0;
396 padding: 0;
397 line-height: 1em;
397 line-height: 1em;
398 list-style-type: none;
398 list-style-type: none;
399
399
400 a {
400 a {
401 display: block;
401 display: block;
402 height: 16px;
402 height: 16px;
403 padding: 8px; //must add up to td height (28px)
403 padding: 8px; //must add up to td height (28px)
404 width: 120px; // set width
404 width: 120px; // set width
405
405
406 &:hover {
406 &:hover {
407 background-color: @grey5;
407 background-color: @grey5;
408 -webkit-transition: background .3s;
408 -webkit-transition: background .3s;
409 -moz-transition: background .3s;
409 -moz-transition: background .3s;
410 -o-transition: background .3s;
410 -o-transition: background .3s;
411 transition: background .3s;
411 transition: background .3s;
412 }
412 }
413 }
413 }
414 }
414 }
415 }
415 }
416 }
416 }
417
417
418 // Header Repository Switcher
418 // Header Repository Switcher
419 // Select2 Dropdown
419 // Select2 Dropdown
420 #select2-drop.select2-drop.repo-switcher-dropdown {
420 #select2-drop.select2-drop.repo-switcher-dropdown {
421 width: auto !important;
421 width: auto !important;
422 margin-top: 5px;
422 margin-top: 5px;
423 padding: 1em 0;
423 padding: 1em 0;
424 text-align: left;
424 text-align: left;
425 .border-radius-bottom(@border-radius);
425 .border-radius-bottom(@border-radius);
426 border-color: transparent;
426 border-color: transparent;
427 color: @grey6;
427 color: @grey6;
428 background-color: @grey2;
428 background-color: @grey2;
429
429
430 input {
430 input {
431 min-width: 90%;
431 min-width: 90%;
432 }
432 }
433
433
434 ul.select2-result-sub {
434 ul.select2-result-sub {
435
435
436 li {
436 li {
437 line-height: 1em;
437 line-height: 1em;
438
438
439 &:hover,
439 &:hover,
440 &.select2-highlighted {
440 &.select2-highlighted {
441 background-color: @grey3;
441 background-color: @grey3;
442 }
442 }
443 }
443 }
444
444
445 &:before { content: none; }
445 &:before { content: none; }
446 }
446 }
447
447
448 ul.select2-results {
448 ul.select2-results {
449 min-width: 200px;
449 min-width: 200px;
450 margin: 0;
450 margin: 0;
451 padding: 0;
451 padding: 0;
452 list-style-type: none;
452 list-style-type: none;
453 overflow-x: visible;
453 overflow-x: visible;
454 overflow-y: scroll;
454 overflow-y: scroll;
455
455
456 li {
456 li {
457 padding: 0 8px;
457 padding: 0 8px;
458 line-height: 1em;
458 line-height: 1em;
459 color: @grey6;
459 color: @grey6;
460
460
461 &>.select2-result-label {
461 &>.select2-result-label {
462 padding: 8px 0;
462 padding: 8px 0;
463 border-bottom: @border-thickness solid @grey3;
463 border-bottom: @border-thickness solid @grey3;
464 white-space: nowrap;
464 white-space: nowrap;
465 color: @grey5;
465 color: @grey5;
466 cursor: pointer;
466 cursor: pointer;
467 }
467 }
468
468
469 &.select2-result-with-children {
469 &.select2-result-with-children {
470 margin: 0;
470 margin: 0;
471 padding: 0;
471 padding: 0;
472 }
472 }
473
473
474 &.select2-result-unselectable > .select2-result-label {
474 &.select2-result-unselectable > .select2-result-label {
475 margin: 0 8px;
475 margin: 0 8px;
476 }
476 }
477
477
478 }
478 }
479 }
479 }
480
480
481 ul.select2-result-sub {
481 ul.select2-result-sub {
482 margin: 0;
482 margin: 0;
483 padding: 0;
483 padding: 0;
484
484
485 li {
485 li {
486 display: block;
486 display: block;
487 margin: 0;
487 margin: 0;
488 border-right: none;
488 border-right: none;
489 line-height: 1em;
489 line-height: 1em;
490 font-family: @text-light;
490 font-family: @text-light;
491 color: @grey2;
491 color: @grey2;
492 list-style-type: none;
492 list-style-type: none;
493
493
494 &:hover {
494 &:hover {
495 background-color: @grey3;
495 background-color: @grey3;
496 }
496 }
497 }
497 }
498 }
498 }
499 }
499 }
500
500
501
501
502 #context-bar {
502 #context-bar {
503 display: block;
503 display: block;
504 margin: 0 auto;
504 margin: 0 auto;
505 padding: 0 @header-padding;
505 padding: 0 @header-padding;
506 background-color: @grey6;
506 background-color: @grey6;
507 border-bottom: @border-thickness solid @grey5;
507 border-bottom: @border-thickness solid @grey5;
508
508
509 .clear {
509 .clear {
510 clear: both;
510 clear: both;
511 }
511 }
512 }
512 }
513
513
514 ul#context-pages {
514 ul#context-pages {
515 li {
515 li {
516 line-height: 1em;
516 line-height: 1em;
517 list-style-type: none;
517 list-style-type: none;
518
518
519 a {
519 a {
520 color: @grey3;
520 color: @grey3;
521 }
521 }
522
522
523 &.active {
523 &.active {
524 // special case, non-variable color
524 // special case, non-variable color
525 border-bottom: 4px solid @nav-grey;
525 border-bottom: 4px solid @nav-grey;
526
526
527 a {
527 a {
528 color: @grey1;
528 color: @grey1;
529 }
529 }
530 }
530 }
531 }
531 }
532 }
532 }
533
533
534 // PAGINATION
534 // PAGINATION
535
535
536 .pagination {
536 .pagination {
537 border: @border-thickness solid @rcblue;
537 border: @border-thickness solid @rcblue;
538 color: @rcblue;
538 color: @rcblue;
539
539
540 .current {
540 .current {
541 color: @grey4;
541 color: @grey4;
542 }
542 }
543 }
543 }
544
544
545 .dataTables_processing {
545 .dataTables_processing {
546 text-align: center;
546 text-align: center;
547 font-size: 1.1em;
547 font-size: 1.1em;
548 position: relative;
548 position: relative;
549 top: 95px;
549 top: 95px;
550 }
550 }
551
551
552 .dataTables_paginate, .pagination-wh {
552 .dataTables_paginate, .pagination-wh {
553 text-align: left;
553 text-align: left;
554 display: inline-block;
554 display: inline-block;
555 border-left: 1px solid @rcblue;
555 border-left: 1px solid @rcblue;
556 float: none;
556 float: none;
557 overflow: hidden;
557 overflow: hidden;
558
558
559 .paginate_button, .pager_curpage,
559 .paginate_button, .pager_curpage,
560 .pager_link, .pg-previous, .pg-next, .pager_dotdot {
560 .pager_link, .pg-previous, .pg-next, .pager_dotdot {
561 display: inline-block;
561 display: inline-block;
562 padding: @menupadding/4 @menupadding;
562 padding: @menupadding/4 @menupadding;
563 border: 1px solid @rcblue;
563 border: 1px solid @rcblue;
564 border-left: 0;
564 border-left: 0;
565 color: @rcblue;
565 color: @rcblue;
566 cursor: pointer;
566 cursor: pointer;
567 float: left;
567 float: left;
568 }
568 }
569
569
570 .pager_curpage, .pager_dotdot,
570 .pager_curpage, .pager_dotdot,
571 .paginate_button.current, .paginate_button.disabled,
571 .paginate_button.current, .paginate_button.disabled,
572 .disabled {
572 .disabled {
573 color: @grey3;
573 color: @grey3;
574 cursor: default;
574 cursor: default;
575 }
575 }
576
576
577 .ellipsis {
577 .ellipsis {
578 display: inline-block;
578 display: inline-block;
579 text-align: left;
579 text-align: left;
580 padding: @menupadding/4 @menupadding;
580 padding: @menupadding/4 @menupadding;
581 border: 1px solid @rcblue;
581 border: 1px solid @rcblue;
582 border-left: 0;
582 border-left: 0;
583 float: left;
583 float: left;
584 }
584 }
585 }
585 }
586
586
587 // SIDEBAR
587 // SIDEBAR
588
588
589 .sidebar {
589 .sidebar {
590 .block-left;
590 .block-left;
591 clear: left;
591 clear: left;
592 max-width: @sidebar-width;
592 max-width: @sidebar-width;
593 margin-right: @sidebarpadding;
593 margin-right: @sidebarpadding;
594 padding-right: @sidebarpadding;
594 padding-right: @sidebarpadding;
595 font-family: @text-regular;
595 font-family: @text-regular;
596 color: @grey1;
596 color: @grey1;
597
597
598 &#graph_nodes {
598 &#graph_nodes {
599 clear:both;
599 clear:both;
600 width: auto;
600 width: auto;
601 margin-left: -100px;
601 margin-left: -100px;
602 padding: 0;
602 padding: 0;
603 border: none;
603 border: none;
604 }
604 }
605
605
606 .nav-pills {
606 .nav-pills {
607 margin: 0;
607 margin: 0;
608 }
608 }
609
609
610 .nav {
610 .nav {
611 list-style: none;
611 list-style: none;
612 padding: 0;
612 padding: 0;
613
613
614 li {
614 li {
615 padding-bottom: @menupadding;
615 padding-bottom: @menupadding;
616 line-height: 1em;
616 line-height: 1em;
617 color: @grey4;
617 color: @grey4;
618 list-style-type: none;
618 list-style-type: none;
619
619
620 &.active a {
620 &.active a {
621 color: @grey2;
621 color: @grey2;
622 }
622 }
623
623
624 a {
624 a {
625 color: @grey4;
625 color: @grey4;
626 }
626 }
627 }
627 }
628
628
629 }
629 }
630 }
630 }
631
631
632 .main_filter_help_box {
632 .main_filter_help_box {
633 padding: 7px 7px;
633 padding: 7px 7px;
634 border-top: 1px solid @grey4;
634 border-top: 1px solid @grey4;
635 border-right: 1px solid @grey4;
635 border-right: 1px solid @grey4;
636 border-bottom: 1px solid @grey4;
636 border-bottom: 1px solid @grey4;
637 display: inline-block;
637 display: inline-block;
638 vertical-align: top;
638 vertical-align: top;
639 margin-left: -7px;
639 background: inherit;
640 background: @grey3;
640 position: absolute;
641 right: 8px;
642 top: 9px;
641 }
643 }
642
644
643 .main_filter_input_box {
645 .main_filter_input_box {
644 display: inline-block;
646 display: inline-block;
645 }
647 }
646
648
647 .main_filter_box {
649 .main_filter_box {
648 margin: 9px 0 0 0;
650 margin: 9px 0 0 0;
649 }
651 }
650
652
651 #main_filter_help {
653 #main_filter_help {
652 background: @grey3;
654 background: @grey3;
653 border: 1px solid black;
655 border: 1px solid black;
654 position: absolute;
656 position: absolute;
655 white-space: pre-wrap;
657 white-space: pre;
656 z-index: 9999;
658 z-index: 9999;
657 color: @nav-grey;
659 color: @nav-grey;
658 margin: 1px 7px;
660 margin: 1px 7px;
659 padding: 0 2px;
661 padding: 0 10px;
660 }
662 }
661
663
662 .main_filter_input {
664 .main_filter_input {
663 padding: 5px;
665 padding: 5px;
664 min-width: 220px;
666 min-width: 260px;
665 color: @nav-grey;
667 color: @nav-grey;
666 background: @grey3;
668 background: @grey3;
667 min-height: 18px;
669 min-height: 18px;
670
671
672 &:active {
673 color: @grey2 !important;
674 background: white !important;
675 }
676 &:focus {
677 color: @grey2 !important;
678 background: white !important;
679 }
668 }
680 }
669
681
682
683
670 .main_filter_input::placeholder {
684 .main_filter_input::placeholder {
671 color: @nav-grey;
685 color: @nav-grey;
672 opacity: 1;
686 opacity: 1;
673 }
687 }
674
688
675 .notice-box {
689 .notice-box {
676 display:block !important;
690 display:block !important;
677 padding: 9px 0 !important;
691 padding: 9px 0 !important;
678 }
692 }
679
693
680 .menulabel-notice {
694 .menulabel-notice {
681 border: 1px solid @color5;
695 border: 1px solid @color5;
682 padding:7px 10px;
696 padding:7px 10px;
683 color: @color5;
697 color: @color5;
684 }
698 }
@@ -1,796 +1,815 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <%include file="/ejs_templates/templates.html"/>
4 <%include file="/ejs_templates/templates.html"/>
5
5
6 <div class="outerwrapper">
6 <div class="outerwrapper">
7 <!-- HEADER -->
7 <!-- HEADER -->
8 <div class="header">
8 <div class="header">
9 <div id="header-inner" class="wrapper">
9 <div id="header-inner" class="wrapper">
10 <div id="logo">
10 <div id="logo">
11 <div class="logo-wrapper">
11 <div class="logo-wrapper">
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
13 </div>
13 </div>
14 %if c.rhodecode_name:
14 %if c.rhodecode_name:
15 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
15 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
16 %endif
16 %endif
17 </div>
17 </div>
18 <!-- MENU BAR NAV -->
18 <!-- MENU BAR NAV -->
19 ${self.menu_bar_nav()}
19 ${self.menu_bar_nav()}
20 <!-- END MENU BAR NAV -->
20 <!-- END MENU BAR NAV -->
21 </div>
21 </div>
22 </div>
22 </div>
23 ${self.menu_bar_subnav()}
23 ${self.menu_bar_subnav()}
24 <!-- END HEADER -->
24 <!-- END HEADER -->
25
25
26 <!-- CONTENT -->
26 <!-- CONTENT -->
27 <div id="content" class="wrapper">
27 <div id="content" class="wrapper">
28
28
29 <rhodecode-toast id="notifications"></rhodecode-toast>
29 <rhodecode-toast id="notifications"></rhodecode-toast>
30
30
31 <div class="main">
31 <div class="main">
32 ${next.main()}
32 ${next.main()}
33 </div>
33 </div>
34 </div>
34 </div>
35 <!-- END CONTENT -->
35 <!-- END CONTENT -->
36
36
37 </div>
37 </div>
38 <!-- FOOTER -->
38 <!-- FOOTER -->
39 <div id="footer">
39 <div id="footer">
40 <div id="footer-inner" class="title wrapper">
40 <div id="footer-inner" class="title wrapper">
41 <div>
41 <div>
42 <p class="footer-link-right">
42 <p class="footer-link-right">
43 % if c.visual.show_version:
43 % if c.visual.show_version:
44 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
44 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
45 % endif
45 % endif
46 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
46 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
47 % if c.visual.rhodecode_support_url:
47 % if c.visual.rhodecode_support_url:
48 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
48 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
49 % endif
49 % endif
50 </p>
50 </p>
51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
52 <p class="server-instance" style="display:${sid}">
52 <p class="server-instance" style="display:${sid}">
53 ## display hidden instance ID if specially defined
53 ## display hidden instance ID if specially defined
54 % if c.rhodecode_instanceid:
54 % if c.rhodecode_instanceid:
55 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
55 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
56 % endif
56 % endif
57 </p>
57 </p>
58 </div>
58 </div>
59 </div>
59 </div>
60 </div>
60 </div>
61
61
62 <!-- END FOOTER -->
62 <!-- END FOOTER -->
63
63
64 ### MAKO DEFS ###
64 ### MAKO DEFS ###
65
65
66 <%def name="menu_bar_subnav()">
66 <%def name="menu_bar_subnav()">
67 </%def>
67 </%def>
68
68
69 <%def name="breadcrumbs(class_='breadcrumbs')">
69 <%def name="breadcrumbs(class_='breadcrumbs')">
70 <div class="${class_}">
70 <div class="${class_}">
71 ${self.breadcrumbs_links()}
71 ${self.breadcrumbs_links()}
72 </div>
72 </div>
73 </%def>
73 </%def>
74
74
75 <%def name="admin_menu()">
75 <%def name="admin_menu()">
76 <ul class="admin_menu submenu">
76 <ul class="admin_menu submenu">
77 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
77 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
78 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
78 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
79 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
79 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
80 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
80 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
81 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
81 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
82 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
82 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
83 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
83 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
84 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
84 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
85 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
85 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
86 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
86 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
87 </ul>
87 </ul>
88 </%def>
88 </%def>
89
89
90
90
91 <%def name="dt_info_panel(elements)">
91 <%def name="dt_info_panel(elements)">
92 <dl class="dl-horizontal">
92 <dl class="dl-horizontal">
93 %for dt, dd, title, show_items in elements:
93 %for dt, dd, title, show_items in elements:
94 <dt>${dt}:</dt>
94 <dt>${dt}:</dt>
95 <dd title="${h.tooltip(title)}">
95 <dd title="${h.tooltip(title)}">
96 %if callable(dd):
96 %if callable(dd):
97 ## allow lazy evaluation of elements
97 ## allow lazy evaluation of elements
98 ${dd()}
98 ${dd()}
99 %else:
99 %else:
100 ${dd}
100 ${dd}
101 %endif
101 %endif
102 %if show_items:
102 %if show_items:
103 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
103 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
104 %endif
104 %endif
105 </dd>
105 </dd>
106
106
107 %if show_items:
107 %if show_items:
108 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
108 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
109 %for item in show_items:
109 %for item in show_items:
110 <dt></dt>
110 <dt></dt>
111 <dd>${item}</dd>
111 <dd>${item}</dd>
112 %endfor
112 %endfor
113 </div>
113 </div>
114 %endif
114 %endif
115
115
116 %endfor
116 %endfor
117 </dl>
117 </dl>
118 </%def>
118 </%def>
119
119
120
120
121 <%def name="gravatar(email, size=16)">
121 <%def name="gravatar(email, size=16)">
122 <%
122 <%
123 if (size > 16):
123 if (size > 16):
124 gravatar_class = 'gravatar gravatar-large'
124 gravatar_class = 'gravatar gravatar-large'
125 else:
125 else:
126 gravatar_class = 'gravatar'
126 gravatar_class = 'gravatar'
127 %>
127 %>
128 <%doc>
128 <%doc>
129 TODO: johbo: For now we serve double size images to make it smooth
129 TODO: johbo: For now we serve double size images to make it smooth
130 for retina. This is how it worked until now. Should be replaced
130 for retina. This is how it worked until now. Should be replaced
131 with a better solution at some point.
131 with a better solution at some point.
132 </%doc>
132 </%doc>
133 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
133 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
134 </%def>
134 </%def>
135
135
136
136
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
138 <% email = h.email_or_none(contact) %>
138 <% email = h.email_or_none(contact) %>
139 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
139 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
140 ${self.gravatar(email, size)}
140 ${self.gravatar(email, size)}
141 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
141 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
142 </div>
142 </div>
143 </%def>
143 </%def>
144
144
145
145
146 ## admin menu used for people that have some admin resources
146 ## admin menu used for people that have some admin resources
147 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
147 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
148 <ul class="submenu">
148 <ul class="submenu">
149 %if repositories:
149 %if repositories:
150 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
150 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
151 %endif
151 %endif
152 %if repository_groups:
152 %if repository_groups:
153 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
153 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
154 %endif
154 %endif
155 %if user_groups:
155 %if user_groups:
156 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
156 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
157 %endif
157 %endif
158 </ul>
158 </ul>
159 </%def>
159 </%def>
160
160
161 <%def name="repo_page_title(repo_instance)">
161 <%def name="repo_page_title(repo_instance)">
162 <div class="title-content">
162 <div class="title-content">
163 <div class="title-main">
163 <div class="title-main">
164 ## SVN/HG/GIT icons
164 ## SVN/HG/GIT icons
165 %if h.is_hg(repo_instance):
165 %if h.is_hg(repo_instance):
166 <i class="icon-hg"></i>
166 <i class="icon-hg"></i>
167 %endif
167 %endif
168 %if h.is_git(repo_instance):
168 %if h.is_git(repo_instance):
169 <i class="icon-git"></i>
169 <i class="icon-git"></i>
170 %endif
170 %endif
171 %if h.is_svn(repo_instance):
171 %if h.is_svn(repo_instance):
172 <i class="icon-svn"></i>
172 <i class="icon-svn"></i>
173 %endif
173 %endif
174
174
175 ## public/private
175 ## public/private
176 %if repo_instance.private:
176 %if repo_instance.private:
177 <i class="icon-repo-private"></i>
177 <i class="icon-repo-private"></i>
178 %else:
178 %else:
179 <i class="icon-repo-public"></i>
179 <i class="icon-repo-public"></i>
180 %endif
180 %endif
181
181
182 ## repo name with group name
182 ## repo name with group name
183 ${h.breadcrumb_repo_link(repo_instance)}
183 ${h.breadcrumb_repo_link(repo_instance)}
184
184
185 </div>
185 </div>
186
186
187 ## FORKED
187 ## FORKED
188 %if repo_instance.fork:
188 %if repo_instance.fork:
189 <p>
189 <p>
190 <i class="icon-code-fork"></i> ${_('Fork of')}
190 <i class="icon-code-fork"></i> ${_('Fork of')}
191 ${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))}
191 ${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))}
192 </p>
192 </p>
193 %endif
193 %endif
194
194
195 ## IMPORTED FROM REMOTE
195 ## IMPORTED FROM REMOTE
196 %if repo_instance.clone_uri:
196 %if repo_instance.clone_uri:
197 <p>
197 <p>
198 <i class="icon-code-fork"></i> ${_('Clone from')}
198 <i class="icon-code-fork"></i> ${_('Clone from')}
199 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
199 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
200 </p>
200 </p>
201 %endif
201 %endif
202
202
203 ## LOCKING STATUS
203 ## LOCKING STATUS
204 %if repo_instance.locked[0]:
204 %if repo_instance.locked[0]:
205 <p class="locking_locked">
205 <p class="locking_locked">
206 <i class="icon-repo-lock"></i>
206 <i class="icon-repo-lock"></i>
207 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
207 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
208 </p>
208 </p>
209 %elif repo_instance.enable_locking:
209 %elif repo_instance.enable_locking:
210 <p class="locking_unlocked">
210 <p class="locking_unlocked">
211 <i class="icon-repo-unlock"></i>
211 <i class="icon-repo-unlock"></i>
212 ${_('Repository not locked. Pull repository to lock it.')}
212 ${_('Repository not locked. Pull repository to lock it.')}
213 </p>
213 </p>
214 %endif
214 %endif
215
215
216 </div>
216 </div>
217 </%def>
217 </%def>
218
218
219 <%def name="repo_menu(active=None)">
219 <%def name="repo_menu(active=None)">
220 <%
220 <%
221 def is_active(selected):
221 def is_active(selected):
222 if selected == active:
222 if selected == active:
223 return "active"
223 return "active"
224 %>
224 %>
225
225
226 <!--- CONTEXT BAR -->
226 <!--- CONTEXT BAR -->
227 <div id="context-bar">
227 <div id="context-bar">
228 <div class="wrapper">
228 <div class="wrapper">
229 <ul id="context-pages" class="navigation horizontal-list">
229 <ul id="context-pages" class="navigation horizontal-list">
230 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
230 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
231 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
231 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
232 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
232 <li class="${is_active('files')}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
233 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
233 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
234 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Search')}</div></a></li>
234 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Search')}</div></a></li>
235
235
236 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
236 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
237 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
237 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
238 <li class="${is_active('showpullrequest')}">
238 <li class="${is_active('showpullrequest')}">
239 <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)}">
239 <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)}">
240 %if c.repository_pull_requests:
240 %if c.repository_pull_requests:
241 <span class="pr_notifications">${c.repository_pull_requests}</span>
241 <span class="pr_notifications">${c.repository_pull_requests}</span>
242 %endif
242 %endif
243 <div class="menulabel">${_('Pull Requests')}</div>
243 <div class="menulabel">${_('Pull Requests')}</div>
244 </a>
244 </a>
245 </li>
245 </li>
246 %endif
246 %endif
247
247
248 <li class="${is_active('options')}">
248 <li class="${is_active('options')}">
249 <a class="menulink dropdown">
249 <a class="menulink dropdown">
250 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
250 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
251 </a>
251 </a>
252 <ul class="submenu">
252 <ul class="submenu">
253 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
253 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
254 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Repository Settings')}</a></li>
254 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Repository Settings')}</a></li>
255 %endif
255 %endif
256 %if c.rhodecode_db_repo.fork:
256 %if c.rhodecode_db_repo.fork:
257 <li>
257 <li>
258 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
258 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
259 href="${h.route_path('repo_compare',
259 href="${h.route_path('repo_compare',
260 repo_name=c.rhodecode_db_repo.fork.repo_name,
260 repo_name=c.rhodecode_db_repo.fork.repo_name,
261 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
261 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
262 source_ref=c.rhodecode_db_repo.landing_rev[1],
262 source_ref=c.rhodecode_db_repo.landing_rev[1],
263 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
263 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
264 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
264 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
265 _query=dict(merge=1))}"
265 _query=dict(merge=1))}"
266 >
266 >
267 ${_('Compare fork')}
267 ${_('Compare fork')}
268 </a>
268 </a>
269 </li>
269 </li>
270 %endif
270 %endif
271
271
272 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
272 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
273 %if c.rhodecode_db_repo.locked[0]:
273 %if c.rhodecode_db_repo.locked[0]:
274 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
274 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
275 %else:
275 %else:
276 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
276 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
277 %endif
277 %endif
278 %endif
278 %endif
279 %if c.rhodecode_user.username != h.DEFAULT_USER:
279 %if c.rhodecode_user.username != h.DEFAULT_USER:
280 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
280 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
281 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
281 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
282 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
282 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
283 %endif
283 %endif
284 %endif
284 %endif
285 </ul>
285 </ul>
286 </li>
286 </li>
287 </ul>
287 </ul>
288 </div>
288 </div>
289 <div class="clear"></div>
289 <div class="clear"></div>
290 </div>
290 </div>
291 % if c.rhodecode_db_repo.archived:
291 % if c.rhodecode_db_repo.archived:
292 <div class="alert alert-warning text-center">
292 <div class="alert alert-warning text-center">
293 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
293 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
294 </div>
294 </div>
295 % endif
295 % endif
296 <!--- END CONTEXT BAR -->
296 <!--- END CONTEXT BAR -->
297
297
298 </%def>
298 </%def>
299
299
300 <%def name="repo_group_page_title(repo_group_instance)">
300 <%def name="repo_group_page_title(repo_group_instance)">
301 <div class="title-content">
301 <div class="title-content">
302 <div class="title-main">
302 <div class="title-main">
303 ## Repository Group icon
303 ## Repository Group icon
304 <i class="icon-folder-close"></i>
304 <i class="icon-folder-close"></i>
305
305
306 ## repo name with group name
306 ## repo name with group name
307 ${h.breadcrumb_repo_group_link(repo_group_instance)}
307 ${h.breadcrumb_repo_group_link(repo_group_instance)}
308 </div>
308 </div>
309
309
310 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
310 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
311 <div class="repo-group-desc">
311 <div class="repo-group-desc">
312 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
312 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
313 </div>
313 </div>
314
314
315 </div>
315 </div>
316 </%def>
316 </%def>
317
317
318 <%def name="repo_group_menu(active=None)">
318 <%def name="repo_group_menu(active=None)">
319 <%
319 <%
320 def is_active(selected):
320 def is_active(selected):
321 if selected == active:
321 if selected == active:
322 return "active"
322 return "active"
323
323
324 is_admin = h.HasPermissionAny('hg.admin')('can create repos index page')
324 is_admin = h.HasPermissionAny('hg.admin')('can create repos index page')
325
325
326 gr_name = c.repo_group.group_name if c.repo_group else None
326 gr_name = c.repo_group.group_name if c.repo_group else None
327 # create repositories with write permission on group is set to true
327 # create repositories with write permission on group is set to true
328 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
328 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
329 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
329 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
330 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
330 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
331
331
332 %>
332 %>
333
333
334 <!--- CONTEXT BAR -->
334 <!--- CONTEXT BAR -->
335 <div id="context-bar">
335 <div id="context-bar">
336 <div class="wrapper">
336 <div class="wrapper">
337 <ul id="context-pages" class="navigation horizontal-list">
337 <ul id="context-pages" class="navigation horizontal-list">
338 <li class="${is_active('home')}"><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></li>
338 <li class="${is_active('home')}"><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></li>
339 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo_group', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Search')}</div></a></li>
339 <li class="${is_active('search')}"><a class="menulink" href="${h.route_path('search_repo_group', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Search')}</div></a></li>
340
340
341 <li class="${is_active('options')}">
341 <li class="${is_active('options')}">
342 <a class="menulink dropdown">
342 <a class="menulink dropdown">
343 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
343 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
344 </a>
344 </a>
345 <ul class="submenu">
345 <ul class="submenu">
346 %if is_admin or group_admin:
346 %if is_admin or group_admin:
347 <li><a 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')}">${_('Group Settings')}</a></li>
347 <li><a 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')}">${_('Group Settings')}</a></li>
348 %endif
348 %endif
349 %if is_admin or group_admin or (group_write and create_on_write):
349 %if is_admin or group_admin or (group_write and create_on_write):
350 <li><a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('Add Repository')}</a></li>
350 <li><a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('Add Repository')}</a></li>
351 %endif
351 %endif
352 %if is_admin or group_admin:
352 %if is_admin or group_admin:
353 <li><a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'Add Parent Group')}</a></li>
353 <li><a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'Add Parent Group')}</a></li>
354 %endif
354 %endif
355 </ul>
355 </ul>
356 </li>
356 </li>
357 </ul>
357 </ul>
358 </div>
358 </div>
359 <div class="clear"></div>
359 <div class="clear"></div>
360 </div>
360 </div>
361
361
362 <!--- END CONTEXT BAR -->
362 <!--- END CONTEXT BAR -->
363
363
364 </%def>
364 </%def>
365
365
366
366
367 <%def name="usermenu(active=False)">
367 <%def name="usermenu(active=False)">
368 ## USER MENU
368 ## USER MENU
369 <li id="quick_login_li" class="${'active' if active else ''}">
369 <li id="quick_login_li" class="${'active' if active else ''}">
370 % if c.rhodecode_user.username == h.DEFAULT_USER:
370 % if c.rhodecode_user.username == h.DEFAULT_USER:
371 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
371 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
372 ${gravatar(c.rhodecode_user.email, 20)}
372 ${gravatar(c.rhodecode_user.email, 20)}
373 <span class="user">
373 <span class="user">
374 <span>${_('Sign in')}</span>
374 <span>${_('Sign in')}</span>
375 </span>
375 </span>
376 </a>
376 </a>
377 % else:
377 % else:
378 ## logged in user
378 ## logged in user
379 <a id="quick_login_link" class="menulink childs">
379 <a id="quick_login_link" class="menulink childs">
380 ${gravatar(c.rhodecode_user.email, 20)}
380 ${gravatar(c.rhodecode_user.email, 20)}
381 <span class="user">
381 <span class="user">
382 <span class="menu_link_user">${c.rhodecode_user.username}</span>
382 <span class="menu_link_user">${c.rhodecode_user.username}</span>
383 <div class="show_more"></div>
383 <div class="show_more"></div>
384 </span>
384 </span>
385 </a>
385 </a>
386 ## subnav with menu for logged in user
386 ## subnav with menu for logged in user
387 <div class="user-menu submenu">
387 <div class="user-menu submenu">
388 <div id="quick_login">
388 <div id="quick_login">
389 %if c.rhodecode_user.username != h.DEFAULT_USER:
389 %if c.rhodecode_user.username != h.DEFAULT_USER:
390 <div class="">
390 <div class="">
391 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
391 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
392 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
392 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
393 <div class="email">${c.rhodecode_user.email}</div>
393 <div class="email">${c.rhodecode_user.email}</div>
394 </div>
394 </div>
395 <div class="">
395 <div class="">
396 <ol class="links">
396 <ol class="links">
397 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
397 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
398 % if c.rhodecode_user.personal_repo_group:
398 % if c.rhodecode_user.personal_repo_group:
399 <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>
399 <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>
400 % endif
400 % endif
401 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
401 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
402 ## bookmark-items
402 ## bookmark-items
403 <li class="bookmark-items">
403 <li class="bookmark-items">
404 ${_('Bookmarks')}
404 ${_('Bookmarks')}
405 <div class="pull-right">
405 <div class="pull-right">
406 <a href="${h.route_path('my_account_bookmarks')}">${_('Manage')}</a>
406 <a href="${h.route_path('my_account_bookmarks')}">${_('Manage')}</a>
407 </div>
407 </div>
408 </li>
408 </li>
409 % if not c.bookmark_items:
409 % if not c.bookmark_items:
410 <li>
410 <li>
411 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
411 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
412 </li>
412 </li>
413 % endif
413 % endif
414 % for item in c.bookmark_items:
414 % for item in c.bookmark_items:
415 <li>
415 <li>
416 % if item.repository:
416 % if item.repository:
417 <div>
417 <div>
418 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
418 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
419 <code>${item.position}</code>
419 <code>${item.position}</code>
420 % if item.repository.repo_type == 'hg':
420 % if item.repository.repo_type == 'hg':
421 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
421 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
422 % elif item.repository.repo_type == 'git':
422 % elif item.repository.repo_type == 'git':
423 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
423 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
424 % elif item.repository.repo_type == 'svn':
424 % elif item.repository.repo_type == 'svn':
425 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
425 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
426 % endif
426 % endif
427 ${(item.title or h.shorter(item.repository.repo_name, 30))}
427 ${(item.title or h.shorter(item.repository.repo_name, 30))}
428 </a>
428 </a>
429 </div>
429 </div>
430 % elif item.repository_group:
430 % elif item.repository_group:
431 <div>
431 <div>
432 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
432 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
433 <code>${item.position}</code>
433 <code>${item.position}</code>
434 <i class="icon-folder-close" title="${_('Repository group')}" style="font-size: 16px"></i>
434 <i class="icon-folder-close" title="${_('Repository group')}" style="font-size: 16px"></i>
435 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
435 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
436 </a>
436 </a>
437 </div>
437 </div>
438 % else:
438 % else:
439 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
439 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
440 <code>${item.position}</code>
440 <code>${item.position}</code>
441 ${item.title}
441 ${item.title}
442 </a>
442 </a>
443 % endif
443 % endif
444 </li>
444 </li>
445 % endfor
445 % endfor
446
446
447 <li class="logout">
447 <li class="logout">
448 ${h.secure_form(h.route_path('logout'), request=request)}
448 ${h.secure_form(h.route_path('logout'), request=request)}
449 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
449 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
450 ${h.end_form()}
450 ${h.end_form()}
451 </li>
451 </li>
452 </ol>
452 </ol>
453 </div>
453 </div>
454 %endif
454 %endif
455 </div>
455 </div>
456 </div>
456 </div>
457 ## unread counter
457 ## unread counter
458 <div class="pill_container">
458 <div class="pill_container">
459 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
459 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
460 </div>
460 </div>
461 % endif
461 % endif
462 </li>
462 </li>
463 </%def>
463 </%def>
464
464
465 <%def name="menu_items(active=None)">
465 <%def name="menu_items(active=None)">
466 <%
466 <%
467 def is_active(selected):
467 def is_active(selected):
468 if selected == active:
468 if selected == active:
469 return "active"
469 return "active"
470 return ""
470 return ""
471 %>
471 %>
472
472
473 <ul id="quick" class="main_nav navigation horizontal-list">
473 <ul id="quick" class="main_nav navigation horizontal-list">
474 ## notice box for important system messages
474 ## notice box for important system messages
475 <li style="display: none">
475 <li style="display: none">
476 <a class="notice-box" href="#openNotice" onclick="showNoticeBox(); return false">
476 <a class="notice-box" href="#openNotice" onclick="showNoticeBox(); return false">
477 <div class="menulabel-notice" >
477 <div class="menulabel-notice" >
478 0
478 0
479 </div>
479 </div>
480 </a>
480 </a>
481 </li>
481 </li>
482
482
483 ## Main filter
483 ## Main filter
484 <li>
484 <li>
485 <div class="menulabel main_filter_box">
485 <div class="menulabel main_filter_box">
486 <div class="main_filter_input_box">
486 <div class="main_filter_input_box">
487 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
487 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
488 </div>
488 </div>
489 <div class="main_filter_help_box">
489 <div class="main_filter_help_box">
490 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
490 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
491 </div>
491 </div>
492 </div>
492 </div>
493
493
494 <div id="main_filter_help" style="display: none">
494 <div id="main_filter_help" style="display: none">
495 Use '/' key to quickly access this field.
495 - Use '/' key to quickly access this field.
496 Enter name of repository, or repository group for quick search.
497
496
498 Prefix query to allow special search:
497 - Enter a name of repository, or repository group for quick search.
498
499 - Prefix query to allow special search:
499
500
500 user:admin, to search for usernames
501 user:admin, to search for usernames
501
502
502 user_group:devops, to search for user groups
503 user_group:devops, to search for user groups
503
504
504 commit:efced4, to search for commits
505 commit:efced4, to search for commits
505
506 </div>
506 </div>
507 </li>
507 </li>
508
508
509 ## ROOT MENU
509 ## ROOT MENU
510 %if c.rhodecode_user.username != h.DEFAULT_USER:
510 %if c.rhodecode_user.username != h.DEFAULT_USER:
511 <li class="${is_active('journal')}">
511 <li class="${is_active('journal')}">
512 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
512 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
513 <div class="menulabel">${_('Journal')}</div>
513 <div class="menulabel">${_('Journal')}</div>
514 </a>
514 </a>
515 </li>
515 </li>
516 %else:
516 %else:
517 <li class="${is_active('journal')}">
517 <li class="${is_active('journal')}">
518 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
518 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
519 <div class="menulabel">${_('Public journal')}</div>
519 <div class="menulabel">${_('Public journal')}</div>
520 </a>
520 </a>
521 </li>
521 </li>
522 %endif
522 %endif
523 <li class="${is_active('gists')}">
523 <li class="${is_active('gists')}">
524 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
524 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
525 <div class="menulabel">${_('Gists')}</div>
525 <div class="menulabel">${_('Gists')}</div>
526 </a>
526 </a>
527 </li>
527 </li>
528 <li class="${is_active('search')}">
528 <li class="${is_active('search')}">
529 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
529 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.route_path('search')}">
530 <div class="menulabel">${_('Search')}</div>
530 <div class="menulabel">${_('Search')}</div>
531 </a>
531 </a>
532 </li>
532 </li>
533 % if h.HasPermissionAll('hg.admin')('access admin main page'):
533 % if h.HasPermissionAll('hg.admin')('access admin main page'):
534 <li class="${is_active('admin')}">
534 <li class="${is_active('admin')}">
535 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
535 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
536 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
536 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
537 </a>
537 </a>
538 ${admin_menu()}
538 ${admin_menu()}
539 </li>
539 </li>
540 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
540 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
541 <li class="${is_active('admin')}">
541 <li class="${is_active('admin')}">
542 <a class="menulink childs" title="${_('Delegated Admin settings')}">
542 <a class="menulink childs" title="${_('Delegated Admin settings')}">
543 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
543 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
544 </a>
544 </a>
545 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
545 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
546 c.rhodecode_user.repository_groups_admin,
546 c.rhodecode_user.repository_groups_admin,
547 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
547 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
548 </li>
548 </li>
549 % endif
549 % endif
550 ## render extra user menu
550 ## render extra user menu
551 ${usermenu(active=(active=='my_account'))}
551 ${usermenu(active=(active=='my_account'))}
552
552
553 % if c.debug_style:
553 % if c.debug_style:
554 <li>
554 <li>
555 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
555 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
556 <div class="menulabel">${_('[Style]')}</div>
556 <div class="menulabel">${_('[Style]')}</div>
557 </a>
557 </a>
558 </li>
558 </li>
559 % endif
559 % endif
560 </ul>
560 </ul>
561
561
562 <script type="text/javascript">
562 <script type="text/javascript">
563 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
563 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
564
564
565 var formatRepoResult = function(result, container, query, escapeMarkup) {
565 var formatRepoResult = function(result, container, query, escapeMarkup) {
566 return function(data, escapeMarkup) {
566 return function(data, escapeMarkup) {
567 if (!data.repo_id){
567 if (!data.repo_id){
568 return data.text; // optgroup text Repositories
568 return data.text; // optgroup text Repositories
569 }
569 }
570
570
571 var tmpl = '';
571 var tmpl = '';
572 var repoType = data['repo_type'];
572 var repoType = data['repo_type'];
573 var repoName = data['text'];
573 var repoName = data['text'];
574
574
575 if(data && data.type == 'repo'){
575 if(data && data.type == 'repo'){
576 if(repoType === 'hg'){
576 if(repoType === 'hg'){
577 tmpl += '<i class="icon-hg"></i> ';
577 tmpl += '<i class="icon-hg"></i> ';
578 }
578 }
579 else if(repoType === 'git'){
579 else if(repoType === 'git'){
580 tmpl += '<i class="icon-git"></i> ';
580 tmpl += '<i class="icon-git"></i> ';
581 }
581 }
582 else if(repoType === 'svn'){
582 else if(repoType === 'svn'){
583 tmpl += '<i class="icon-svn"></i> ';
583 tmpl += '<i class="icon-svn"></i> ';
584 }
584 }
585 if(data['private']){
585 if(data['private']){
586 tmpl += '<i class="icon-lock" ></i> ';
586 tmpl += '<i class="icon-lock" ></i> ';
587 }
587 }
588 else if(visualShowPublicIcon){
588 else if(visualShowPublicIcon){
589 tmpl += '<i class="icon-unlock-alt"></i> ';
589 tmpl += '<i class="icon-unlock-alt"></i> ';
590 }
590 }
591 }
591 }
592 tmpl += escapeMarkup(repoName);
592 tmpl += escapeMarkup(repoName);
593 return tmpl;
593 return tmpl;
594
594
595 }(result, escapeMarkup);
595 }(result, escapeMarkup);
596 };
596 };
597
597
598 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
598 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
599 return function(data, escapeMarkup) {
599 return function(data, escapeMarkup) {
600 if (!data.repo_group_id){
600 if (!data.repo_group_id){
601 return data.text; // optgroup text Repositories
601 return data.text; // optgroup text Repositories
602 }
602 }
603
603
604 var tmpl = '';
604 var tmpl = '';
605 var repoGroupName = data['text'];
605 var repoGroupName = data['text'];
606
606
607 if(data){
607 if(data){
608
608
609 tmpl += '<i class="icon-folder-close"></i> ';
609 tmpl += '<i class="icon-folder-close"></i> ';
610
610
611 }
611 }
612 tmpl += escapeMarkup(repoGroupName);
612 tmpl += escapeMarkup(repoGroupName);
613 return tmpl;
613 return tmpl;
614
614
615 }(result, escapeMarkup);
615 }(result, escapeMarkup);
616 };
616 };
617
617
618
618
619 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
619 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
620
620
621 if (value.split(':').length === 2) {
621 if (value.split(':').length === 2) {
622 value = value.split(':')[1]
622 value = value.split(':')[1]
623 }
623 }
624
624
625 var searchType = data['type'];
625 var searchType = data['type'];
626 var valueDisplay = data['value_display'];
626 var valueDisplay = data['value_display'];
627
627
628 var escapeRegExChars = function (value) {
628 var escapeRegExChars = function (value) {
629 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
629 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
630 };
630 };
631 var pattern = '(' + escapeRegExChars(value) + ')';
631 var pattern = '(' + escapeRegExChars(value) + ')';
632
632
633 var getRepoIcon = function(repo_type) {
634 if (repo_type === 'hg') {
635 return '<i class="icon-hg"></i> ';
636 }
637 else if (repo_type === 'git') {
638 return '<i class="icon-git"></i> ';
639 }
640 else if (repo_type === 'svn') {
641 return '<i class="icon-svn"></i> ';
642 }
643 return ''
644 };
645
633 // highlight match
646 // highlight match
634 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
647 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
635 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
648 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
636
649
637 var icon = '';
650 var icon = '';
638
651
639 if (searchType === 'hint') {
652 if (searchType === 'hint') {
640 icon += '<i class="icon-folder-close"></i> ';
653 icon += '<i class="icon-folder-close"></i> ';
641 }
654 }
655 // full text search
642 else if (searchType === 'search') {
656 else if (searchType === 'search') {
643 icon += '<i class="icon-more"></i> ';
657 icon += '<i class="icon-more"></i> ';
644 }
658 }
659 // repository
645 else if (searchType === 'repo') {
660 else if (searchType === 'repo') {
646 if (data['repo_type'] === 'hg') {
661
647 icon += '<i class="icon-hg"></i> ';
662 var repoIcon = getRepoIcon(data['repo_type']);
648 }
663 icon += repoIcon;
649 else if (data['repo_type'] === 'git') {
664
650 icon += '<i class="icon-git"></i> ';
651 }
652 else if (data['repo_type'] === 'svn') {
653 icon += '<i class="icon-svn"></i> ';
654 }
655 if (data['private']) {
665 if (data['private']) {
656 icon += '<i class="icon-lock" ></i> ';
666 icon += '<i class="icon-lock" ></i> ';
657 }
667 }
658 else if (visualShowPublicIcon) {
668 else if (visualShowPublicIcon) {
659 icon += '<i class="icon-unlock-alt"></i> ';
669 icon += '<i class="icon-unlock-alt"></i> ';
660 }
670 }
661 }
671 }
672 // repository groups
662 else if (searchType === 'repo_group') {
673 else if (searchType === 'repo_group') {
663 icon += '<i class="icon-folder-close"></i> ';
674 icon += '<i class="icon-folder-close"></i> ';
664 }
675 }
676 // user group
665 else if (searchType === 'user_group') {
677 else if (searchType === 'user_group') {
666 icon += '<i class="icon-group"></i> ';
678 icon += '<i class="icon-group"></i> ';
667 }
679 }
668 else if (searchType === 'user') {
680 else if (searchType === 'user') {
669 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
681 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
670 }
682 }
683 // commit
671 else if (searchType === 'commit') {
684 else if (searchType === 'commit') {
672 icon += '<i class="icon-tag"></i>';
685 var repo_data = data['repo_data'];
686 var repoIcon = getRepoIcon(repo_data['repository_type']);
687 if (repoIcon) {
688 icon += repoIcon;
689 } else {
690 icon += '<i class="icon-tag"></i>';
691 }
673 }
692 }
674
693
675 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
694 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
676 return tmpl.format(icon, valueDisplay);
695 return tmpl.format(icon, valueDisplay);
677 };
696 };
678
697
679 var handleSelect = function(element, suggestion) {
698 var handleSelect = function(element, suggestion) {
680 if (suggestion.type === "hint") {
699 if (suggestion.type === "hint") {
681 // we skip action
700 // we skip action
682 $('#main_filter').focus();
701 $('#main_filter').focus();
683 } else {
702 } else {
684 window.location = suggestion['url'];
703 window.location = suggestion['url'];
685 }
704 }
686 };
705 };
687 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
706 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
688 if (queryLowerCase.split(':').length === 2) {
707 if (queryLowerCase.split(':').length === 2) {
689 queryLowerCase = queryLowerCase.split(':')[1]
708 queryLowerCase = queryLowerCase.split(':')[1]
690 }
709 }
691 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
710 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
692 };
711 };
693
712
694 $('#main_filter').autocomplete({
713 $('#main_filter').autocomplete({
695 serviceUrl: pyroutes.url('goto_switcher_data'),
714 serviceUrl: pyroutes.url('goto_switcher_data'),
696 params: {"search_context": templateContext.search_context},
715 params: {"search_context": templateContext.search_context},
697 minChars:2,
716 minChars:2,
698 maxHeight:400,
717 maxHeight:400,
699 deferRequestBy: 300, //miliseconds
718 deferRequestBy: 300, //miliseconds
700 tabDisabled: true,
719 tabDisabled: true,
701 autoSelectFirst: true,
720 autoSelectFirst: true,
702 formatResult: autocompleteMainFilterFormatResult,
721 formatResult: autocompleteMainFilterFormatResult,
703 lookupFilter: autocompleteMainFilterResult,
722 lookupFilter: autocompleteMainFilterResult,
704 onSelect: function (element, suggestion) {
723 onSelect: function (element, suggestion) {
705 handleSelect(element, suggestion);
724 handleSelect(element, suggestion);
706 return false;
725 return false;
707 },
726 },
708 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
727 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
709 if (jqXHR !== 'abort') {
728 if (jqXHR !== 'abort') {
710 alert("Error during search.\nError code: {0}".format(textStatus));
729 alert("Error during search.\nError code: {0}".format(textStatus));
711 window.location = '';
730 window.location = '';
712 }
731 }
713 }
732 }
714 });
733 });
715
734
716 showMainFilterBox = function () {
735 showMainFilterBox = function () {
717 $('#main_filter_help').toggle();
736 $('#main_filter_help').toggle();
718 }
737 };
719
738
720 </script>
739 </script>
721 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
740 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
722 </%def>
741 </%def>
723
742
724 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
743 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
725 <div class="modal-dialog">
744 <div class="modal-dialog">
726 <div class="modal-content">
745 <div class="modal-content">
727 <div class="modal-header">
746 <div class="modal-header">
728 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
747 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
729 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
748 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
730 </div>
749 </div>
731 <div class="modal-body">
750 <div class="modal-body">
732 <div class="block-left">
751 <div class="block-left">
733 <table class="keyboard-mappings">
752 <table class="keyboard-mappings">
734 <tbody>
753 <tbody>
735 <tr>
754 <tr>
736 <th></th>
755 <th></th>
737 <th>${_('Site-wide shortcuts')}</th>
756 <th>${_('Site-wide shortcuts')}</th>
738 </tr>
757 </tr>
739 <%
758 <%
740 elems = [
759 elems = [
741 ('/', 'Use quick search box'),
760 ('/', 'Use quick search box'),
742 ('g h', 'Goto home page'),
761 ('g h', 'Goto home page'),
743 ('g g', 'Goto my private gists page'),
762 ('g g', 'Goto my private gists page'),
744 ('g G', 'Goto my public gists page'),
763 ('g G', 'Goto my public gists page'),
745 ('g 0-9', 'Goto bookmarked items from 0-9'),
764 ('g 0-9', 'Goto bookmarked items from 0-9'),
746 ('n r', 'New repository page'),
765 ('n r', 'New repository page'),
747 ('n g', 'New gist page'),
766 ('n g', 'New gist page'),
748 ]
767 ]
749 %>
768 %>
750 %for key, desc in elems:
769 %for key, desc in elems:
751 <tr>
770 <tr>
752 <td class="keys">
771 <td class="keys">
753 <span class="key tag">${key}</span>
772 <span class="key tag">${key}</span>
754 </td>
773 </td>
755 <td>${desc}</td>
774 <td>${desc}</td>
756 </tr>
775 </tr>
757 %endfor
776 %endfor
758 </tbody>
777 </tbody>
759 </table>
778 </table>
760 </div>
779 </div>
761 <div class="block-left">
780 <div class="block-left">
762 <table class="keyboard-mappings">
781 <table class="keyboard-mappings">
763 <tbody>
782 <tbody>
764 <tr>
783 <tr>
765 <th></th>
784 <th></th>
766 <th>${_('Repositories')}</th>
785 <th>${_('Repositories')}</th>
767 </tr>
786 </tr>
768 <%
787 <%
769 elems = [
788 elems = [
770 ('g s', 'Goto summary page'),
789 ('g s', 'Goto summary page'),
771 ('g c', 'Goto changelog page'),
790 ('g c', 'Goto changelog page'),
772 ('g f', 'Goto files page'),
791 ('g f', 'Goto files page'),
773 ('g F', 'Goto files page with file search activated'),
792 ('g F', 'Goto files page with file search activated'),
774 ('g p', 'Goto pull requests page'),
793 ('g p', 'Goto pull requests page'),
775 ('g o', 'Goto repository settings'),
794 ('g o', 'Goto repository settings'),
776 ('g O', 'Goto repository permissions settings'),
795 ('g O', 'Goto repository permissions settings'),
777 ]
796 ]
778 %>
797 %>
779 %for key, desc in elems:
798 %for key, desc in elems:
780 <tr>
799 <tr>
781 <td class="keys">
800 <td class="keys">
782 <span class="key tag">${key}</span>
801 <span class="key tag">${key}</span>
783 </td>
802 </td>
784 <td>${desc}</td>
803 <td>${desc}</td>
785 </tr>
804 </tr>
786 %endfor
805 %endfor
787 </tbody>
806 </tbody>
788 </table>
807 </table>
789 </div>
808 </div>
790 </div>
809 </div>
791 <div class="modal-footer">
810 <div class="modal-footer">
792 </div>
811 </div>
793 </div><!-- /.modal-content -->
812 </div><!-- /.modal-content -->
794 </div><!-- /.modal-dialog -->
813 </div><!-- /.modal-dialog -->
795 </div><!-- /.modal -->
814 </div><!-- /.modal -->
796
815
General Comments 0
You need to be logged in to leave comments. Login now