##// END OF EJS Templates
go-to search: updated logic of goto switcher...
marcink -
r3556:a75b51f8 default
parent child Browse files
Show More
@@ -33,7 +33,7 b' from rhodecode.lib.index import searcher'
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_, case, 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
@@ -105,21 +105,27 b' class HomeView(BaseAppView):'
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, repo_group_name='', 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))\
116 .order_by(Repository.repo_name)\
117 .filter(Repository.archived.isnot(true()))\
115 .filter(Repository.archived.isnot(true()))\
118 .filter(or_(
116 .filter(or_(
119 # generate multiple IN to fix limitation problems
117 # generate multiple IN to fix limitation problems
120 *in_filter_generator(Repository.repo_id, allowed_ids)
118 *in_filter_generator(Repository.repo_id, allowed_ids)
121 ))
119 ))
122
120
121 query = query.order_by(case(
122 [
123 (Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
124 ],
125 ))
126 query = query.order_by(func.length(Repository.repo_name))
127 query = query.order_by(Repository.repo_name)
128
123 if repo_type:
129 if repo_type:
124 query = query.filter(Repository.repo_type == repo_type)
130 query = query.filter(Repository.repo_type == repo_type)
125
131
@@ -145,20 +151,26 b' class HomeView(BaseAppView):'
145 }
151 }
146 for obj in acl_iter]
152 for obj in acl_iter]
147
153
148 def _get_repo_group_list(self, name_contains=None, limit=20):
154 def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
149 org_query = name_contains
155 org_query = name_contains
150 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
156 allowed_ids = self._rhodecode_user.repo_group_acl_ids(
151 ['group.read', 'group.write', 'group.admin'],
157 ['group.read', 'group.write', 'group.admin'],
152 cache=False, name_filter=name_contains) or [-1]
158 cache=False, name_filter=name_contains) or [-1]
153
159
154 query = RepoGroup.query()\
160 query = RepoGroup.query()\
155 .order_by(func.length(RepoGroup.group_name))\
156 .order_by(RepoGroup.group_name) \
157 .filter(or_(
161 .filter(or_(
158 # generate multiple IN to fix limitation problems
162 # generate multiple IN to fix limitation problems
159 *in_filter_generator(RepoGroup.group_id, allowed_ids)
163 *in_filter_generator(RepoGroup.group_id, allowed_ids)
160 ))
164 ))
161
165
166 query = query.order_by(case(
167 [
168 (RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
169 ],
170 ))
171 query = query.order_by(func.length(RepoGroup.group_name))
172 query = query.order_by(RepoGroup.group_name)
173
162 if name_contains:
174 if name_contains:
163 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
175 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
164 query = query.filter(
176 query = query.filter(
@@ -183,11 +195,17 b' class HomeView(BaseAppView):'
183 def _get_user_list(self, name_contains=None, limit=20):
195 def _get_user_list(self, name_contains=None, limit=20):
184 org_query = name_contains
196 org_query = name_contains
185 if not name_contains:
197 if not name_contains:
186 return []
198 return [], False
187
199
188 name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
200 # TODO(marcink): should all logged in users be allowed to search others?
201 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
202 if not allowed_user_search:
203 return [], False
204
205 name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
189 if len(name_contains) != 1:
206 if len(name_contains) != 1:
190 return []
207 return [], False
208
191 name_contains = name_contains[0]
209 name_contains = name_contains[0]
192
210
193 query = User.query()\
211 query = User.query()\
@@ -207,22 +225,28 b' class HomeView(BaseAppView):'
207 {
225 {
208 'id': obj.user_id,
226 'id': obj.user_id,
209 'value': org_query,
227 'value': org_query,
210 'value_display': obj.username,
228 'value_display': 'user: `{}`'.format(obj.username),
211 'type': 'user',
229 'type': 'user',
212 'icon_link': h.gravatar_url(obj.email, 30),
230 'icon_link': h.gravatar_url(obj.email, 30),
213 'url': h.route_path(
231 'url': h.route_path(
214 'user_profile', username=obj.username)
232 'user_profile', username=obj.username)
215 }
233 }
216 for obj in acl_iter]
234 for obj in acl_iter], True
217
235
218 def _get_user_groups_list(self, name_contains=None, limit=20):
236 def _get_user_groups_list(self, name_contains=None, limit=20):
219 org_query = name_contains
237 org_query = name_contains
220 if not name_contains:
238 if not name_contains:
221 return []
239 return [], False
222
240
223 name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
241 # TODO(marcink): should all logged in users be allowed to search others?
242 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
243 if not allowed_user_search:
244 return [], False
245
246 name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
224 if len(name_contains) != 1:
247 if len(name_contains) != 1:
225 return []
248 return [], False
249
226 name_contains = name_contains[0]
250 name_contains = name_contains[0]
227
251
228 query = UserGroup.query()\
252 query = UserGroup.query()\
@@ -241,27 +265,34 b' class HomeView(BaseAppView):'
241 {
265 {
242 'id': obj.users_group_id,
266 'id': obj.users_group_id,
243 'value': org_query,
267 'value': org_query,
244 'value_display': obj.users_group_name,
268 'value_display': 'user_group: `{}`'.format(obj.users_group_name),
245 'type': 'user_group',
269 'type': 'user_group',
246 'url': h.route_path(
270 'url': h.route_path(
247 'user_group_profile', user_group_name=obj.users_group_name)
271 'user_group_profile', user_group_name=obj.users_group_name)
248 }
272 }
249 for obj in acl_iter]
273 for obj in acl_iter], True
250
274
251 def _get_hash_commit_list(self, auth_user, searcher, query):
275 def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
276 repo_name = repo_group_name = None
277 if repo:
278 repo_name = repo.repo_name
279 if repo_group:
280 repo_group_name = repo_group.group_name
281
252 org_query = query
282 org_query = query
253 if not query or len(query) < 3 or not searcher:
283 if not query or len(query) < 3 or not searcher:
254 return []
284 return [], False
255
285
256 commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
286 commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
257
287
258 if len(commit_hashes) != 1:
288 if len(commit_hashes) != 1:
259 return []
289 return [], False
290
260 commit_hash = commit_hashes[0]
291 commit_hash = commit_hashes[0]
261
292
262 result = searcher.search(
293 result = searcher.search(
263 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
294 'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
264 raise_on_exc=False)
295 repo_name, repo_group_name, raise_on_exc=False)
265
296
266 commits = []
297 commits = []
267 for entry in result['results']:
298 for entry in result['results']:
@@ -286,22 +317,29 b' class HomeView(BaseAppView):'
286 }
317 }
287
318
288 commits.append(commit_entry)
319 commits.append(commit_entry)
289 return commits
320 return commits, True
290
321
291 def _get_path_list(self, auth_user, searcher, query):
322 def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
323 repo_name = repo_group_name = None
324 if repo:
325 repo_name = repo.repo_name
326 if repo_group:
327 repo_group_name = repo_group.group_name
328
292 org_query = query
329 org_query = query
293 if not query or len(query) < 3 or not searcher:
330 if not query or len(query) < 3 or not searcher:
294 return []
331 return [], False
295
332
296 paths_re = re.compile('(?:file:)(.{1,})').findall(query)
333 paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
297 if len(paths_re) != 1:
334 if len(paths_re) != 1:
298 return []
335 return [], False
336
299 file_path = paths_re[0]
337 file_path = paths_re[0]
300
338
301 search_path = searcher.escape_specials(file_path)
339 search_path = searcher.escape_specials(file_path)
302 result = searcher.search(
340 result = searcher.search(
303 'file.raw:*{}*'.format(search_path), 'path', auth_user,
341 'file.raw:*{}*'.format(search_path), 'path', auth_user,
304 raise_on_exc=False)
342 repo_name, repo_group_name, raise_on_exc=False)
305
343
306 files = []
344 files = []
307 for entry in result['results']:
345 for entry in result['results']:
@@ -327,7 +365,7 b' class HomeView(BaseAppView):'
327 }
365 }
328
366
329 files.append(file_entry)
367 files.append(file_entry)
330 return files
368 return files, True
331
369
332 @LoginRequired()
370 @LoginRequired()
333 @view_config(
371 @view_config(
@@ -405,8 +443,7 b' class HomeView(BaseAppView):'
405 qry = query
443 qry = query
406 return {'q': qry, 'type': 'content'}
444 return {'q': qry, 'type': 'content'}
407 label = u'File search for `{}` in this repository.'.format(query)
445 label = u'File search for `{}` in this repository.'.format(query)
408 queries.append(
446 file_qry = {
409 {
410 'id': -10,
447 'id': -10,
411 'value': query,
448 'value': query,
412 'value_display': label,
449 'value_display': label,
@@ -415,7 +452,6 b' class HomeView(BaseAppView):'
415 repo_name=repo_name,
452 repo_name=repo_name,
416 _query=query_modifier())
453 _query=query_modifier())
417 }
454 }
418 )
419
455
420 # commits
456 # commits
421 def query_modifier():
457 def query_modifier():
@@ -423,8 +459,7 b' class HomeView(BaseAppView):'
423 return {'q': qry, 'type': 'commit'}
459 return {'q': qry, 'type': 'commit'}
424
460
425 label = u'Commit search for `{}` in this repository.'.format(query)
461 label = u'Commit search for `{}` in this repository.'.format(query)
426 queries.append(
462 commit_qry = {
427 {
428 'id': -20,
463 'id': -20,
429 'value': query,
464 'value': query,
430 'value_display': label,
465 'value_display': label,
@@ -433,7 +468,13 b' class HomeView(BaseAppView):'
433 repo_name=repo_name,
468 repo_name=repo_name,
434 _query=query_modifier())
469 _query=query_modifier())
435 }
470 }
436 )
471
472 if repo_context in ['commit', 'changelog']:
473 queries.extend([commit_qry, file_qry])
474 elif repo_context in ['files', 'summary']:
475 queries.extend([file_qry, commit_qry])
476 else:
477 queries.extend([commit_qry, file_qry])
437
478
438 elif is_es_6 and repo_group_name:
479 elif is_es_6 and repo_group_name:
439 # files
480 # files
@@ -442,8 +483,7 b' class HomeView(BaseAppView):'
442 return {'q': qry, 'type': 'content'}
483 return {'q': qry, 'type': 'content'}
443
484
444 label = u'File search for `{}` in this repository group'.format(query)
485 label = u'File search for `{}` in this repository group'.format(query)
445 queries.append(
486 file_qry = {
446 {
447 'id': -30,
487 'id': -30,
448 'value': query,
488 'value': query,
449 'value_display': label,
489 'value_display': label,
@@ -452,7 +492,6 b' class HomeView(BaseAppView):'
452 repo_group_name=repo_group_name,
492 repo_group_name=repo_group_name,
453 _query=query_modifier())
493 _query=query_modifier())
454 }
494 }
455 )
456
495
457 # commits
496 # commits
458 def query_modifier():
497 def query_modifier():
@@ -460,8 +499,7 b' class HomeView(BaseAppView):'
460 return {'q': qry, 'type': 'commit'}
499 return {'q': qry, 'type': 'commit'}
461
500
462 label = u'Commit search for `{}` in this repository group'.format(query)
501 label = u'Commit search for `{}` in this repository group'.format(query)
463 queries.append(
502 commit_qry = {
464 {
465 'id': -40,
503 'id': -40,
466 'value': query,
504 'value': query,
467 'value_display': label,
505 'value_display': label,
@@ -470,8 +508,15 b' class HomeView(BaseAppView):'
470 repo_group_name=repo_group_name,
508 repo_group_name=repo_group_name,
471 _query=query_modifier())
509 _query=query_modifier())
472 }
510 }
473 )
474
511
512 if repo_context in ['commit', 'changelog']:
513 queries.extend([commit_qry, file_qry])
514 elif repo_context in ['files', 'summary']:
515 queries.extend([file_qry, commit_qry])
516 else:
517 queries.extend([commit_qry, file_qry])
518
519 # Global, not scoped
475 if not queries:
520 if not queries:
476 queries.append(
521 queries.append(
477 {
522 {
@@ -510,57 +555,76 b' class HomeView(BaseAppView):'
510 if not query:
555 if not query:
511 return {'suggestions': res}
556 return {'suggestions': res}
512
557
558 def no_match(name):
559 return {
560 'id': -1,
561 'value': "",
562 'value_display': name,
563 'type': 'text',
564 'url': ""
565 }
513 searcher = searcher_from_config(self.request.registry.settings)
566 searcher = searcher_from_config(self.request.registry.settings)
514 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
567 has_specialized_search = False
515 res.append(_q)
516
568
569 # set repo context
570 repo = None
571 repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
572 if repo_id:
573 repo = Repository.get(repo_id)
574
575 # set group context
576 repo_group = None
517 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
577 repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
518 if repo_group_id:
578 if repo_group_id:
519 repo_group = RepoGroup.get(repo_group_id)
579 repo_group = RepoGroup.get(repo_group_id)
520 composed_hint = '{}/{}'.format(repo_group.group_name, query)
580 prefix_match = False
521 show_hint = not query.startswith(repo_group.group_name)
522 if repo_group and show_hint:
523 hint = u'Repository search inside: `{}`'.format(composed_hint)
524 res.append({
525 'id': -1,
526 'value': composed_hint,
527 'value_display': hint,
528 'type': 'hint',
529 'url': ""
530 })
531
581
532 repo_groups = self._get_repo_group_list(query)
582 # user: type search
533 for serialized_repo_group in repo_groups:
583 if not prefix_match:
534 res.append(serialized_repo_group)
584 users, prefix_match = self._get_user_list(query)
535
585 if users:
536 repos = self._get_repo_list(query)
586 has_specialized_search = True
537 for serialized_repo in repos:
538 res.append(serialized_repo)
539
540 # TODO(marcink): should all logged in users be allowed to search others?
541 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
542 if allowed_user_search:
543 users = self._get_user_list(query)
544 for serialized_user in users:
587 for serialized_user in users:
545 res.append(serialized_user)
588 res.append(serialized_user)
589 elif prefix_match:
590 has_specialized_search = True
591 res.append(no_match('No matching users found'))
546
592
547 user_groups = self._get_user_groups_list(query)
593 # user_group: type search
594 if not prefix_match:
595 user_groups, prefix_match = self._get_user_groups_list(query)
596 if user_groups:
597 has_specialized_search = True
548 for serialized_user_group in user_groups:
598 for serialized_user_group in user_groups:
549 res.append(serialized_user_group)
599 res.append(serialized_user_group)
600 elif prefix_match:
601 has_specialized_search = True
602 res.append(no_match('No matching user groups found'))
550
603
551 commits = self._get_hash_commit_list(c.auth_user, searcher, query)
604 # FTS commit: type search
605 if not prefix_match:
606 commits, prefix_match = self._get_hash_commit_list(
607 c.auth_user, searcher, query, repo, repo_group)
552 if commits:
608 if commits:
609 has_specialized_search = True
553 unique_repos = collections.OrderedDict()
610 unique_repos = collections.OrderedDict()
554 for commit in commits:
611 for commit in commits:
555 repo_name = commit['repo']
612 repo_name = commit['repo']
556 unique_repos.setdefault(repo_name, []).append(commit)
613 unique_repos.setdefault(repo_name, []).append(commit)
557
614
558 for repo, commits in unique_repos.items():
615 for _repo, commits in unique_repos.items():
559 for commit in commits:
616 for commit in commits:
560 res.append(commit)
617 res.append(commit)
618 elif prefix_match:
619 has_specialized_search = True
620 res.append(no_match('No matching commits found'))
561
621
562 paths = self._get_path_list(c.auth_user, searcher, query)
622 # FTS file: type search
623 if not prefix_match:
624 paths, prefix_match = self._get_path_list(
625 c.auth_user, searcher, query, repo, repo_group)
563 if paths:
626 if paths:
627 has_specialized_search = True
564 unique_repos = collections.OrderedDict()
628 unique_repos = collections.OrderedDict()
565 for path in paths:
629 for path in paths:
566 repo_name = path['repo']
630 repo_name = path['repo']
@@ -569,6 +633,29 b' class HomeView(BaseAppView):'
569 for repo, paths in unique_repos.items():
633 for repo, paths in unique_repos.items():
570 for path in paths:
634 for path in paths:
571 res.append(path)
635 res.append(path)
636 elif prefix_match:
637 has_specialized_search = True
638 res.append(no_match('No matching files found'))
639
640 # main suggestions
641 if not has_specialized_search:
642 repo_group_name = ''
643 if repo_group:
644 repo_group_name = repo_group.group_name
645
646 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
647 res.append(_q)
648
649 repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
650 for serialized_repo_group in repo_groups:
651 res.append(serialized_repo_group)
652
653 repos = self._get_repo_list(query, repo_group_name=repo_group_name)
654 for serialized_repo in repos:
655 res.append(serialized_repo)
656
657 if not repos and not repo_groups:
658 res.append(no_match('No matches found'))
572
659
573 return {'suggestions': res}
660 return {'suggestions': res}
574
661
@@ -2037,6 +2037,6 b' def get_repo_view_type(request):'
2037 'repo_files': 'files',
2037 'repo_files': 'files',
2038 'repo_summary': 'summary',
2038 'repo_summary': 'summary',
2039 'repo_commit': 'commit'
2039 'repo_commit': 'commit'
2040 }
2040
2041
2041 }
2042 return route_to_view_type.get(route_name)
2042 return route_to_view_type.get(route_name)
@@ -39,7 +39,7 b' from sqlalchemy import ('
39 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
39 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
40 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
40 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
41 Text, Float, PickleType)
41 Text, Float, PickleType)
42 from sqlalchemy.sql.expression import true, false
42 from sqlalchemy.sql.expression import true, false, case
43 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
43 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
44 from sqlalchemy.orm import (
44 from sqlalchemy.orm import (
45 relationship, joinedload, class_mapper, validates, aliased)
45 relationship, joinedload, class_mapper, validates, aliased)
@@ -644,6 +644,40 b' ul#context-pages {'
644
644
645 .main_filter_input_box {
645 .main_filter_input_box {
646 display: inline-block;
646 display: inline-block;
647
648 .searchItems {
649 display:flex;
650 background: #666666;
651 padding: 0px;
652
653 a {
654 border: none !important;
655 }
656 }
657
658 .searchTag {
659 line-height: 28px;
660 padding: 0px 4px;
661
662 .tag {
663 color: @nav-grey;
664 border-color: @nav-grey;
665 }
666 }
667
668 .searchTagFilter {
669 background-color: @grey3 !important;
670 }
671
672 .searchTagHelp {
673 background-color: @grey2 !important;
674 }
675 .searchTagHelp:hover {
676 background-color: @grey2 !important;
677 }
678 .searchTagInput {
679 background-color: @grey3 !important;
680 }
647 }
681 }
648
682
649 .main_filter_box {
683 .main_filter_box {
@@ -667,7 +701,8 b' ul#context-pages {'
667 color: @nav-grey;
701 color: @nav-grey;
668 background: @grey3;
702 background: @grey3;
669 min-height: 18px;
703 min-height: 18px;
670
704 border:none;
705 border-radius: 0;
671
706
672 &:active {
707 &:active {
673 color: @grey2 !important;
708 color: @grey2 !important;
@@ -528,7 +528,19 b''
528 if ($.isFunction(serviceUrl)) {
528 if ($.isFunction(serviceUrl)) {
529 serviceUrl = serviceUrl.call(that.element, query);
529 serviceUrl = serviceUrl.call(that.element, query);
530 }
530 }
531 cacheKey = serviceUrl + '?' + $.param(params || {});
531
532 var callParams = {};
533 //make an evaluated copy of params
534 $.each(params, function(index, value) {
535 if($.isFunction(value)){
536 callParams[index] = value();
537 }
538 else {
539 callParams[index] = value;
540 }
541 });
542
543 cacheKey = serviceUrl + '?' + $.param(callParams);
532 response = that.cachedResponse[cacheKey];
544 response = that.cachedResponse[cacheKey];
533 }
545 }
534
546
@@ -536,7 +548,7 b''
536 that.suggestions = response.suggestions;
548 that.suggestions = response.suggestions;
537 that.suggest();
549 that.suggest();
538 } else if (!that.isBadQuery(query)) {
550 } else if (!that.isBadQuery(query)) {
539 if (options.onSearchStart.call(that.element, options.params) === false) {
551 if (options.onSearchStart.call(that.element, params) === false) {
540 return;
552 return;
541 }
553 }
542 if (that.currentRequest) {
554 if (that.currentRequest) {
@@ -233,7 +233,6 b''
233 <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>
233 <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>
234 <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>
234 <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>
235 <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>
235 <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>
236 <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>
237
236
238 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
237 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
239 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
238 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
@@ -338,7 +337,6 b''
338 <div class="wrapper">
337 <div class="wrapper">
339 <ul id="context-pages" class="navigation horizontal-list">
338 <ul id="context-pages" class="navigation horizontal-list">
340 <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('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>
341 <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>
342
340
343 <li class="${is_active('options')}">
341 <li class="${is_active('options')}">
344 <a class="menulink dropdown">
342 <a class="menulink dropdown">
@@ -486,10 +484,35 b''
486 <li>
484 <li>
487 <div class="menulabel main_filter_box">
485 <div class="menulabel main_filter_box">
488 <div class="main_filter_input_box">
486 <div class="main_filter_input_box">
487 <ul class="searchItems">
488
489 % if c.template_context['search_context']['repo_id']:
490 <li class="searchTag searchTagFilter searchTagHidable" >
491 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
492 <span class="tag">
493 This repo
494 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
495 </span>
496 ##</a>
497 </li>
498 % elif c.template_context['search_context']['repo_group_id']:
499 <li class="searchTag searchTagFilter searchTagHidable">
500 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
501 <span class="tag">
502 This group
503 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
504 </span>
505 ##</a>
506 </li>
507 % endif
508
509 <li class="searchTagInput">
489 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
510 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
490 </div>
511 </li>
491 <div class="main_filter_help_box">
512 <li class="searchTag searchTagHelp">
492 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
513 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
514 </li>
515 </ul>
493 </div>
516 </div>
494 </div>
517 </div>
495
518
@@ -500,13 +523,21 b''
500
523
501 - Prefix query to allow special search:
524 - Prefix query to allow special search:
502
525
503 user:admin, to search for usernames
526 user:admin, to search for usernames, always global
527
528 user_group:devops, to search for user groups, always global
504
529
505 user_group:devops, to search for user groups
530 commit:efced4, to search for commits, scoped to repositories or groups
531
532 file:models.py, to search for file paths, scoped to repositories or groups
506
533
507 commit:efced4, to search for commits
534 % if c.template_context['search_context']['repo_id']:
508
535 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
509 file:models.py, to search for file paths
536 % elif c.template_context['search_context']['repo_group_id']:
537 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
538 % else:
539 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
540 % endif
510 </div>
541 </div>
511 </li>
542 </li>
512
543
@@ -622,20 +653,9 b''
622 }(result, escapeMarkup);
653 }(result, escapeMarkup);
623 };
654 };
624
655
625
626 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
627
628 if (value.split(':').length === 2) {
629 value = value.split(':')[1]
630 }
631
632 var searchType = data['type'];
633 var valueDisplay = data['value_display'];
634
635 var escapeRegExChars = function (value) {
656 var escapeRegExChars = function (value) {
636 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
657 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
637 };
658 };
638 var pattern = '(' + escapeRegExChars(value) + ')';
639
659
640 var getRepoIcon = function(repo_type) {
660 var getRepoIcon = function(repo_type) {
641 if (repo_type === 'hg') {
661 if (repo_type === 'hg') {
@@ -650,9 +670,23 b''
650 return ''
670 return ''
651 };
671 };
652
672
653 // highlight match
673 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
674
675 if (value.split(':').length === 2) {
676 value = value.split(':')[1]
677 }
678
679 var searchType = data['type'];
680 var valueDisplay = data['value_display'];
681
682 var pattern = '(' + escapeRegExChars(value) + ')';
683
654 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
684 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
685
686 // highlight match
687 if (searchType != 'text') {
655 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
688 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
689 }
656
690
657 var icon = '';
691 var icon = '';
658
692
@@ -684,6 +718,7 b''
684 else if (searchType === 'user_group') {
718 else if (searchType === 'user_group') {
685 icon += '<i class="icon-group"></i> ';
719 icon += '<i class="icon-group"></i> ';
686 }
720 }
721 // user
687 else if (searchType === 'user') {
722 else if (searchType === 'user') {
688 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
723 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
689 }
724 }
@@ -707,6 +742,10 b''
707 icon += '<i class="icon-tag"></i>';
742 icon += '<i class="icon-tag"></i>';
708 }
743 }
709 }
744 }
745 // generic text
746 else if (searchType === 'text') {
747 icon = '';
748 }
710
749
711 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
750 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
712 return tmpl.format(icon, valueDisplay);
751 return tmpl.format(icon, valueDisplay);
@@ -716,25 +755,52 b''
716 if (suggestion.type === "hint") {
755 if (suggestion.type === "hint") {
717 // we skip action
756 // we skip action
718 $('#main_filter').focus();
757 $('#main_filter').focus();
758 }
759 else if (suggestion.type === "text") {
760 // we skip action
761 $('#main_filter').focus();
762
719 } else {
763 } else {
720 window.location = suggestion['url'];
764 window.location = suggestion['url'];
721 }
765 }
722 };
766 };
767
723 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
768 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
724 if (queryLowerCase.split(':').length === 2) {
769 if (queryLowerCase.split(':').length === 2) {
725 queryLowerCase = queryLowerCase.split(':')[1]
770 queryLowerCase = queryLowerCase.split(':')[1]
726 }
771 }
772 if (suggestion.type === "text") {
773 // special case we don't want to "skip" display for
774 return true
775 }
727 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
776 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
728 };
777 };
729
778
779 var cleanContext = {
780 repo_view_type: null,
781
782 repo_id: null,
783 repo_name: "",
784
785 repo_group_id: null,
786 repo_group_name: null
787 };
788 var removeGoToFilter = function () {
789 $('.searchTagHidable').hide();
790 $('#main_filter').autocomplete(
791 'setOptions', {params:{search_context: cleanContext}});
792 };
793
730 $('#main_filter').autocomplete({
794 $('#main_filter').autocomplete({
731 serviceUrl: pyroutes.url('goto_switcher_data'),
795 serviceUrl: pyroutes.url('goto_switcher_data'),
732 params: {"search_context": templateContext.search_context},
796 params: {
797 "search_context": templateContext.search_context
798 },
733 minChars:2,
799 minChars:2,
734 maxHeight:400,
800 maxHeight:400,
735 deferRequestBy: 300, //miliseconds
801 deferRequestBy: 300, //miliseconds
736 tabDisabled: true,
802 tabDisabled: true,
737 autoSelectFirst: true,
803 autoSelectFirst: false,
738 formatResult: autocompleteMainFilterFormatResult,
804 formatResult: autocompleteMainFilterFormatResult,
739 lookupFilter: autocompleteMainFilterResult,
805 lookupFilter: autocompleteMainFilterResult,
740 onSelect: function (element, suggestion) {
806 onSelect: function (element, suggestion) {
@@ -753,6 +819,18 b''
753 $('#main_filter_help').toggle();
819 $('#main_filter_help').toggle();
754 };
820 };
755
821
822 $('#main_filter').on('keydown.autocomplete', function (e) {
823
824 var BACKSPACE = 8;
825 var el = $(e.currentTarget);
826 if(e.which === BACKSPACE){
827 var inputVal = el.val();
828 if (inputVal === ""){
829 removeGoToFilter()
830 }
831 }
832 });
833
756 </script>
834 </script>
757 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
835 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
758 </%def>
836 </%def>
@@ -7,7 +7,7 b" go_import_header = ''"
7 if hasattr(c, 'rhodecode_db_repo'):
7 if hasattr(c, 'rhodecode_db_repo'):
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10 ## check repo context
10 c.template_context['repo_id'] = c.rhodecode_db_repo.repo_id
11 c.template_context['repo_view_type'] = h.get_repo_view_type(request)
11 c.template_context['repo_view_type'] = h.get_repo_view_type(request)
12
12
13 if getattr(c, 'repo_group', None):
13 if getattr(c, 'repo_group', None):
@@ -29,6 +29,7 b" c.template_context['default_user'] = {"
29 c.template_context['search_context'] = {
29 c.template_context['search_context'] = {
30 'repo_group_id': c.template_context.get('repo_group_id'),
30 'repo_group_id': c.template_context.get('repo_group_id'),
31 'repo_group_name': c.template_context.get('repo_group_name'),
31 'repo_group_name': c.template_context.get('repo_group_name'),
32 'repo_id': c.template_context.get('repo_id'),
32 'repo_name': c.template_context.get('repo_name'),
33 'repo_name': c.template_context.get('repo_name'),
33 'repo_view_type': c.template_context.get('repo_view_type'),
34 'repo_view_type': c.template_context.get('repo_view_type'),
34 }
35 }
@@ -37,9 +37,9 b''
37
37
38 <%def name="menu_bar_subnav()">
38 <%def name="menu_bar_subnav()">
39 %if c.repo_name:
39 %if c.repo_name:
40 ${self.repo_menu(active='search')}
40 ${self.repo_menu(active='summary')}
41 %elif c.repo_group_name:
41 %elif c.repo_group_name:
42 ${self.repo_group_menu(active='search')}
42 ${self.repo_group_menu(active='home')}
43 %endif
43 %endif
44 </%def>
44 </%def>
45
45
General Comments 0
You need to be logged in to leave comments. Login now