##// 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,17 +443,15 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 {
447 'id': -10,
410 'id': -10,
448 'value': query,
411 'value': query,
449 'value_display': label,
412 'value_display': label,
450 'type': 'search',
413 'type': 'search',
451 'url': h.route_path('search_repo',
414 'url': h.route_path('search_repo',
452 repo_name=repo_name,
415 repo_name=repo_name,
453 _query=query_modifier())
416 _query=query_modifier())
417 }
454 }
418 )
419
455
420 # commits
456 # commits
421 def query_modifier():
457 def query_modifier():
@@ -423,17 +459,22 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 {
463 'id': -20,
428 'id': -20,
464 'value': query,
429 'value': query,
465 'value_display': label,
430 'value_display': label,
466 'type': 'search',
431 'type': 'search',
467 'url': h.route_path('search_repo',
432 'url': h.route_path('search_repo',
468 repo_name=repo_name,
433 repo_name=repo_name,
469 _query=query_modifier())
434 _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,17 +483,15 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 {
487 'id': -30,
447 'id': -30,
488 'value': query,
448 'value': query,
489 'value_display': label,
449 'value_display': label,
490 'type': 'search',
450 'type': 'search',
491 'url': h.route_path('search_repo_group',
451 'url': h.route_path('search_repo_group',
492 repo_group_name=repo_group_name,
452 repo_group_name=repo_group_name,
493 _query=query_modifier())
453 _query=query_modifier())
454 }
494 }
455 )
456
495
457 # commits
496 # commits
458 def query_modifier():
497 def query_modifier():
@@ -460,18 +499,24 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 {
503 'id': -40,
465 'id': -40,
504 'value': query,
466 'value': query,
505 'value_display': label,
467 'value_display': label,
506 'type': 'search',
468 'type': 'search',
507 'url': h.route_path('search_repo_group',
469 'url': h.route_path('search_repo_group',
508 repo_group_name=repo_group_name,
470 repo_group_name=repo_group_name,
509 _query=query_modifier())
471 _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,65 +555,107 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)
581
522 if repo_group and show_hint:
582 # user: type search
523 hint = u'Repository search inside: `{}`'.format(composed_hint)
583 if not prefix_match:
524 res.append({
584 users, prefix_match = self._get_user_list(query)
525 'id': -1,
585 if users:
526 'value': composed_hint,
586 has_specialized_search = True
527 'value_display': hint,
587 for serialized_user in users:
528 'type': 'hint',
588 res.append(serialized_user)
529 'url': ""
589 elif prefix_match:
530 })
590 has_specialized_search = True
591 res.append(no_match('No matching users found'))
531
592
532 repo_groups = self._get_repo_group_list(query)
593 # user_group: type search
533 for serialized_repo_group in repo_groups:
594 if not prefix_match:
534 res.append(serialized_repo_group)
595 user_groups, prefix_match = self._get_user_groups_list(query)
596 if user_groups:
597 has_specialized_search = True
598 for serialized_user_group in user_groups:
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'))
535
603
536 repos = self._get_repo_list(query)
604 # FTS commit: type search
537 for serialized_repo in repos:
605 if not prefix_match:
538 res.append(serialized_repo)
606 commits, prefix_match = self._get_hash_commit_list(
607 c.auth_user, searcher, query, repo, repo_group)
608 if commits:
609 has_specialized_search = True
610 unique_repos = collections.OrderedDict()
611 for commit in commits:
612 repo_name = commit['repo']
613 unique_repos.setdefault(repo_name, []).append(commit)
539
614
540 # TODO(marcink): should all logged in users be allowed to search others?
615 for _repo, commits in unique_repos.items():
541 allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
616 for commit in commits:
542 if allowed_user_search:
617 res.append(commit)
543 users = self._get_user_list(query)
618 elif prefix_match:
544 for serialized_user in users:
619 has_specialized_search = True
545 res.append(serialized_user)
620 res.append(no_match('No matching commits found'))
546
621
547 user_groups = self._get_user_groups_list(query)
622 # FTS file: type search
548 for serialized_user_group in user_groups:
623 if not prefix_match:
549 res.append(serialized_user_group)
624 paths, prefix_match = self._get_path_list(
625 c.auth_user, searcher, query, repo, repo_group)
626 if paths:
627 has_specialized_search = True
628 unique_repos = collections.OrderedDict()
629 for path in paths:
630 repo_name = path['repo']
631 unique_repos.setdefault(repo_name, []).append(path)
550
632
551 commits = self._get_hash_commit_list(c.auth_user, searcher, query)
633 for repo, paths in unique_repos.items():
552 if commits:
634 for path in paths:
553 unique_repos = collections.OrderedDict()
635 res.append(path)
554 for commit in commits:
636 elif prefix_match:
555 repo_name = commit['repo']
637 has_specialized_search = True
556 unique_repos.setdefault(repo_name, []).append(commit)
638 res.append(no_match('No matching files found'))
557
639
558 for repo, commits in unique_repos.items():
640 # main suggestions
559 for commit in commits:
641 if not has_specialized_search:
560 res.append(commit)
642 repo_group_name = ''
643 if repo_group:
644 repo_group_name = repo_group.group_name
561
645
562 paths = self._get_path_list(c.auth_user, searcher, query)
646 for _q in self._get_default_search_queries(self.request.GET, searcher, query):
563 if paths:
647 res.append(_q)
564 unique_repos = collections.OrderedDict()
648
565 for path in paths:
649 repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
566 repo_name = path['repo']
650 for serialized_repo_group in repo_groups:
567 unique_repos.setdefault(repo_name, []).append(path)
651 res.append(serialized_repo_group)
568
652
569 for repo, paths in unique_repos.items():
653 repos = self._get_repo_list(query, repo_group_name=repo_group_name)
570 for path in paths:
654 for serialized_repo in repos:
571 res.append(path)
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">
489 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
487 <ul class="searchItems">
490 </div>
488
491 <div class="main_filter_help_box">
489 % if c.template_context['search_context']['repo_id']:
492 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
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">
510 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
511 </li>
512 <li class="searchTag searchTagHelp">
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,6 +653,22 b''
622 }(result, escapeMarkup);
653 }(result, escapeMarkup);
623 };
654 };
624
655
656 var escapeRegExChars = function (value) {
657 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
658 };
659
660 var getRepoIcon = function(repo_type) {
661 if (repo_type === 'hg') {
662 return '<i class="icon-hg"></i> ';
663 }
664 else if (repo_type === 'git') {
665 return '<i class="icon-git"></i> ';
666 }
667 else if (repo_type === 'svn') {
668 return '<i class="icon-svn"></i> ';
669 }
670 return ''
671 };
625
672
626 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
673 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
627
674
@@ -632,27 +679,14 b''
632 var searchType = data['type'];
679 var searchType = data['type'];
633 var valueDisplay = data['value_display'];
680 var valueDisplay = data['value_display'];
634
681
635 var escapeRegExChars = function (value) {
636 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
637 };
638 var pattern = '(' + escapeRegExChars(value) + ')';
682 var pattern = '(' + escapeRegExChars(value) + ')';
639
683
640 var getRepoIcon = function(repo_type) {
684 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
641 if (repo_type === 'hg') {
642 return '<i class="icon-hg"></i> ';
643 }
644 else if (repo_type === 'git') {
645 return '<i class="icon-git"></i> ';
646 }
647 else if (repo_type === 'svn') {
648 return '<i class="icon-svn"></i> ';
649 }
650 return ''
651 };
652
685
653 // highlight match
686 // highlight match
654 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
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