Show More
@@ -33,7 +33,7 b' from rhodecode.lib.index import searcher' | |||
|
33 | 33 | from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int |
|
34 | 34 | from rhodecode.lib.ext_json import json |
|
35 | 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 | 37 | from rhodecode.model.repo import RepoModel |
|
38 | 38 | from rhodecode.model.repo_group import RepoGroupModel |
|
39 | 39 | from rhodecode.model.scm import RepoGroupList, RepoList |
@@ -105,21 +105,27 b' class HomeView(BaseAppView):' | |||
|
105 | 105 | |
|
106 | 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 | 109 | org_query = name_contains |
|
110 | 110 | allowed_ids = self._rhodecode_user.repo_acl_ids( |
|
111 | 111 | ['repository.read', 'repository.write', 'repository.admin'], |
|
112 | 112 | cache=False, name_filter=name_contains) or [-1] |
|
113 | 113 | |
|
114 | 114 | query = Repository.query()\ |
|
115 | .order_by(func.length(Repository.repo_name))\ | |
|
116 | .order_by(Repository.repo_name)\ | |
|
117 | 115 | .filter(Repository.archived.isnot(true()))\ |
|
118 | 116 | .filter(or_( |
|
119 | 117 | # generate multiple IN to fix limitation problems |
|
120 | 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 | 129 | if repo_type: |
|
124 | 130 | query = query.filter(Repository.repo_type == repo_type) |
|
125 | 131 | |
@@ -145,20 +151,26 b' class HomeView(BaseAppView):' | |||
|
145 | 151 | } |
|
146 | 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 | 155 | org_query = name_contains |
|
150 | 156 | allowed_ids = self._rhodecode_user.repo_group_acl_ids( |
|
151 | 157 | ['group.read', 'group.write', 'group.admin'], |
|
152 | 158 | cache=False, name_filter=name_contains) or [-1] |
|
153 | 159 | |
|
154 | 160 | query = RepoGroup.query()\ |
|
155 | .order_by(func.length(RepoGroup.group_name))\ | |
|
156 | .order_by(RepoGroup.group_name) \ | |
|
157 | 161 | .filter(or_( |
|
158 | 162 | # generate multiple IN to fix limitation problems |
|
159 | 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 | 174 | if name_contains: |
|
163 | 175 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
164 | 176 | query = query.filter( |
@@ -183,11 +195,17 b' class HomeView(BaseAppView):' | |||
|
183 | 195 | def _get_user_list(self, name_contains=None, limit=20): |
|
184 | 196 | org_query = name_contains |
|
185 | 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 | 206 | if len(name_contains) != 1: |
|
190 | return [] | |
|
207 | return [], False | |
|
208 | ||
|
191 | 209 | name_contains = name_contains[0] |
|
192 | 210 | |
|
193 | 211 | query = User.query()\ |
@@ -207,22 +225,28 b' class HomeView(BaseAppView):' | |||
|
207 | 225 | { |
|
208 | 226 | 'id': obj.user_id, |
|
209 | 227 | 'value': org_query, |
|
210 | 'value_display': obj.username, | |
|
228 | 'value_display': 'user: `{}`'.format(obj.username), | |
|
211 | 229 | 'type': 'user', |
|
212 | 230 | 'icon_link': h.gravatar_url(obj.email, 30), |
|
213 | 231 | 'url': h.route_path( |
|
214 | 232 | 'user_profile', username=obj.username) |
|
215 | 233 | } |
|
216 | for obj in acl_iter] | |
|
234 | for obj in acl_iter], True | |
|
217 | 235 | |
|
218 | 236 | def _get_user_groups_list(self, name_contains=None, limit=20): |
|
219 | 237 | org_query = name_contains |
|
220 | 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 | 247 | if len(name_contains) != 1: |
|
225 | return [] | |
|
248 | return [], False | |
|
249 | ||
|
226 | 250 | name_contains = name_contains[0] |
|
227 | 251 | |
|
228 | 252 | query = UserGroup.query()\ |
@@ -241,27 +265,34 b' class HomeView(BaseAppView):' | |||
|
241 | 265 | { |
|
242 | 266 | 'id': obj.users_group_id, |
|
243 | 267 | 'value': org_query, |
|
244 | 'value_display': obj.users_group_name, | |
|
268 | 'value_display': 'user_group: `{}`'.format(obj.users_group_name), | |
|
245 | 269 | 'type': 'user_group', |
|
246 | 270 | 'url': h.route_path( |
|
247 | 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 | 282 | org_query = query |
|
253 | 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 | 288 | if len(commit_hashes) != 1: |
|
259 | return [] | |
|
289 | return [], False | |
|
290 | ||
|
260 | 291 | commit_hash = commit_hashes[0] |
|
261 | 292 | |
|
262 | 293 | result = searcher.search( |
|
263 | 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 | 297 | commits = [] |
|
267 | 298 | for entry in result['results']: |
@@ -286,22 +317,29 b' class HomeView(BaseAppView):' | |||
|
286 | 317 | } |
|
287 | 318 | |
|
288 | 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 | 329 | org_query = query |
|
293 | 330 | if not query or len(query) < 3 or not searcher: |
|
294 | return [] | |
|
331 | return [], False | |
|
295 | 332 | |
|
296 |
paths_re = re.compile('(?:file: |
|
|
333 | paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query) | |
|
297 | 334 | if len(paths_re) != 1: |
|
298 | return [] | |
|
335 | return [], False | |
|
336 | ||
|
299 | 337 | file_path = paths_re[0] |
|
300 | 338 | |
|
301 | 339 | search_path = searcher.escape_specials(file_path) |
|
302 | 340 | result = searcher.search( |
|
303 | 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 | 344 | files = [] |
|
307 | 345 | for entry in result['results']: |
@@ -327,7 +365,7 b' class HomeView(BaseAppView):' | |||
|
327 | 365 | } |
|
328 | 366 | |
|
329 | 367 | files.append(file_entry) |
|
330 | return files | |
|
368 | return files, True | |
|
331 | 369 | |
|
332 | 370 | @LoginRequired() |
|
333 | 371 | @view_config( |
@@ -405,8 +443,7 b' class HomeView(BaseAppView):' | |||
|
405 | 443 | qry = query |
|
406 | 444 | return {'q': qry, 'type': 'content'} |
|
407 | 445 | label = u'File search for `{}` in this repository.'.format(query) |
|
408 | queries.append( | |
|
409 | { | |
|
446 | file_qry = { | |
|
410 | 447 |
|
|
411 | 448 |
|
|
412 | 449 |
|
@@ -415,7 +452,6 b' class HomeView(BaseAppView):' | |||
|
415 | 452 |
|
|
416 | 453 |
|
|
417 | 454 | } |
|
418 | ) | |
|
419 | 455 | |
|
420 | 456 | # commits |
|
421 | 457 | def query_modifier(): |
@@ -423,8 +459,7 b' class HomeView(BaseAppView):' | |||
|
423 | 459 | return {'q': qry, 'type': 'commit'} |
|
424 | 460 | |
|
425 | 461 | label = u'Commit search for `{}` in this repository.'.format(query) |
|
426 | queries.append( | |
|
427 | { | |
|
462 | commit_qry = { | |
|
428 | 463 |
|
|
429 | 464 |
|
|
430 | 465 |
|
@@ -433,7 +468,13 b' class HomeView(BaseAppView):' | |||
|
433 | 468 |
|
|
434 | 469 |
|
|
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 | 479 | elif is_es_6 and repo_group_name: |
|
439 | 480 | # files |
@@ -442,8 +483,7 b' class HomeView(BaseAppView):' | |||
|
442 | 483 | return {'q': qry, 'type': 'content'} |
|
443 | 484 | |
|
444 | 485 | label = u'File search for `{}` in this repository group'.format(query) |
|
445 | queries.append( | |
|
446 | { | |
|
486 | file_qry = { | |
|
447 | 487 |
|
|
448 | 488 |
|
|
449 | 489 |
|
@@ -452,7 +492,6 b' class HomeView(BaseAppView):' | |||
|
452 | 492 |
|
|
453 | 493 |
|
|
454 | 494 | } |
|
455 | ) | |
|
456 | 495 | |
|
457 | 496 | # commits |
|
458 | 497 | def query_modifier(): |
@@ -460,8 +499,7 b' class HomeView(BaseAppView):' | |||
|
460 | 499 | return {'q': qry, 'type': 'commit'} |
|
461 | 500 | |
|
462 | 501 | label = u'Commit search for `{}` in this repository group'.format(query) |
|
463 | queries.append( | |
|
464 | { | |
|
502 | commit_qry = { | |
|
465 | 503 |
|
|
466 | 504 |
|
|
467 | 505 |
|
@@ -470,8 +508,15 b' class HomeView(BaseAppView):' | |||
|
470 | 508 |
|
|
471 | 509 |
|
|
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 | 520 | if not queries: |
|
476 | 521 | queries.append( |
|
477 | 522 | { |
@@ -510,57 +555,76 b' class HomeView(BaseAppView):' | |||
|
510 | 555 | if not query: |
|
511 | 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 | 566 | searcher = searcher_from_config(self.request.registry.settings) |
|
514 | for _q in self._get_default_search_queries(self.request.GET, searcher, query): | |
|
515 | res.append(_q) | |
|
567 | has_specialized_search = False | |
|
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 | 577 | repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]')) |
|
518 | 578 | if repo_group_id: |
|
519 | 579 | repo_group = RepoGroup.get(repo_group_id) |
|
520 | composed_hint = '{}/{}'.format(repo_group.group_name, query) | |
|
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 | }) | |
|
580 | prefix_match = False | |
|
531 | 581 | |
|
532 | repo_groups = self._get_repo_group_list(query) | |
|
533 | for serialized_repo_group in repo_groups: | |
|
534 | res.append(serialized_repo_group) | |
|
535 | ||
|
536 | repos = self._get_repo_list(query) | |
|
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) | |
|
582 | # user: type search | |
|
583 | if not prefix_match: | |
|
584 | users, prefix_match = self._get_user_list(query) | |
|
585 | if users: | |
|
586 | has_specialized_search = True | |
|
544 | 587 | for serialized_user in users: |
|
545 | 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 | 598 | for serialized_user_group in user_groups: |
|
549 | 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 | 608 | if commits: |
|
609 | has_specialized_search = True | |
|
553 | 610 | unique_repos = collections.OrderedDict() |
|
554 | 611 | for commit in commits: |
|
555 | 612 | repo_name = commit['repo'] |
|
556 | 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 | 616 | for commit in commits: |
|
560 | 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 | 626 | if paths: |
|
627 | has_specialized_search = True | |
|
564 | 628 | unique_repos = collections.OrderedDict() |
|
565 | 629 | for path in paths: |
|
566 | 630 | repo_name = path['repo'] |
@@ -569,6 +633,29 b' class HomeView(BaseAppView):' | |||
|
569 | 633 | for repo, paths in unique_repos.items(): |
|
570 | 634 | for path in paths: |
|
571 | 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 | 660 | return {'suggestions': res} |
|
574 | 661 |
@@ -2037,6 +2037,6 b' def get_repo_view_type(request):' | |||
|
2037 | 2037 | 'repo_files': 'files', |
|
2038 | 2038 | 'repo_summary': 'summary', |
|
2039 | 2039 | 'repo_commit': 'commit' |
|
2040 | } | |
|
2040 | 2041 | |
|
2041 | } | |
|
2042 | 2042 | return route_to_view_type.get(route_name) |
@@ -39,7 +39,7 b' from sqlalchemy import (' | |||
|
39 | 39 | Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column, |
|
40 | 40 | Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary, |
|
41 | 41 | Text, Float, PickleType) |
|
42 | from sqlalchemy.sql.expression import true, false | |
|
42 | from sqlalchemy.sql.expression import true, false, case | |
|
43 | 43 | from sqlalchemy.sql.functions import coalesce, count # pragma: no cover |
|
44 | 44 | from sqlalchemy.orm import ( |
|
45 | 45 | relationship, joinedload, class_mapper, validates, aliased) |
@@ -644,6 +644,40 b' ul#context-pages {' | |||
|
644 | 644 | |
|
645 | 645 | .main_filter_input_box { |
|
646 | 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 | 683 | .main_filter_box { |
@@ -667,7 +701,8 b' ul#context-pages {' | |||
|
667 | 701 | color: @nav-grey; |
|
668 | 702 | background: @grey3; |
|
669 | 703 | min-height: 18px; |
|
670 | ||
|
704 | border:none; | |
|
705 | border-radius: 0; | |
|
671 | 706 | |
|
672 | 707 | &:active { |
|
673 | 708 | color: @grey2 !important; |
@@ -528,7 +528,19 b'' | |||
|
528 | 528 | if ($.isFunction(serviceUrl)) { |
|
529 | 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 | 544 | response = that.cachedResponse[cacheKey]; |
|
533 | 545 | } |
|
534 | 546 | |
@@ -536,7 +548,7 b'' | |||
|
536 | 548 | that.suggestions = response.suggestions; |
|
537 | 549 | that.suggest(); |
|
538 | 550 | } else if (!that.isBadQuery(query)) { |
|
539 |
if (options.onSearchStart.call(that.element, |
|
|
551 | if (options.onSearchStart.call(that.element, params) === false) { | |
|
540 | 552 | return; |
|
541 | 553 | } |
|
542 | 554 | if (that.currentRequest) { |
@@ -233,7 +233,6 b'' | |||
|
233 | 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 | 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 | 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 | 237 | ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()" |
|
239 | 238 | %if c.rhodecode_db_repo.repo_type in ['git','hg']: |
@@ -338,7 +337,6 b'' | |||
|
338 | 337 | <div class="wrapper"> |
|
339 | 338 | <ul id="context-pages" class="navigation horizontal-list"> |
|
340 | 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 | 341 | <li class="${is_active('options')}"> |
|
344 | 342 | <a class="menulink dropdown"> |
@@ -486,10 +484,35 b'' | |||
|
486 | 484 | <li> |
|
487 | 485 | <div class="menulabel main_filter_box"> |
|
488 | 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 | 510 | <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/> |
|
490 |
</ |
|
|
491 |
< |
|
|
511 | </li> | |
|
512 | <li class="searchTag searchTagHelp"> | |
|
492 | 513 | <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a> |
|
514 | </li> | |
|
515 | </ul> | |
|
493 | 516 | </div> |
|
494 | 517 | </div> |
|
495 | 518 | |
@@ -500,13 +523,21 b'' | |||
|
500 | 523 | |
|
501 | 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 | |
|
508 | ||
|
509 | file:models.py, to search for file paths | |
|
534 | % if c.template_context['search_context']['repo_id']: | |
|
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> | |
|
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 | 541 | </div> |
|
511 | 542 | </li> |
|
512 | 543 | |
@@ -622,20 +653,9 b'' | |||
|
622 | 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 | 656 |
|
|
636 | 657 |
|
|
637 | 658 |
|
|
638 | var pattern = '(' + escapeRegExChars(value) + ')'; | |
|
639 | 659 | |
|
640 | 660 |
|
|
641 | 661 |
|
@@ -650,9 +670,23 b'' | |||
|
650 | 670 |
|
|
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 | 684 | valueDisplay = Select2.util.escapeMarkup(valueDisplay); |
|
685 | ||
|
686 | // highlight match | |
|
687 | if (searchType != 'text') { | |
|
655 | 688 | valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); |
|
689 | } | |
|
656 | 690 | |
|
657 | 691 | var icon = ''; |
|
658 | 692 | |
@@ -684,6 +718,7 b'' | |||
|
684 | 718 | else if (searchType === 'user_group') { |
|
685 | 719 | icon += '<i class="icon-group"></i> '; |
|
686 | 720 | } |
|
721 | // user | |
|
687 | 722 | else if (searchType === 'user') { |
|
688 | 723 | icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']); |
|
689 | 724 | } |
@@ -707,6 +742,10 b'' | |||
|
707 | 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 | 750 | var tmpl = '<div class="ac-container-wrap">{0}{1}</div>'; |
|
712 | 751 | return tmpl.format(icon, valueDisplay); |
@@ -716,25 +755,52 b'' | |||
|
716 | 755 | if (suggestion.type === "hint") { |
|
717 | 756 | // we skip action |
|
718 | 757 | $('#main_filter').focus(); |
|
758 | } | |
|
759 | else if (suggestion.type === "text") { | |
|
760 | // we skip action | |
|
761 | $('#main_filter').focus(); | |
|
762 | ||
|
719 | 763 | } else { |
|
720 | 764 | window.location = suggestion['url']; |
|
721 | 765 | } |
|
722 | 766 | }; |
|
767 | ||
|
723 | 768 | var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) { |
|
724 | 769 | if (queryLowerCase.split(':').length === 2) { |
|
725 | 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 | 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 | 794 | $('#main_filter').autocomplete({ |
|
731 | 795 | serviceUrl: pyroutes.url('goto_switcher_data'), |
|
732 | params: {"search_context": templateContext.search_context}, | |
|
796 | params: { | |
|
797 | "search_context": templateContext.search_context | |
|
798 | }, | |
|
733 | 799 | minChars:2, |
|
734 | 800 | maxHeight:400, |
|
735 | 801 | deferRequestBy: 300, //miliseconds |
|
736 | 802 | tabDisabled: true, |
|
737 |
autoSelectFirst: |
|
|
803 | autoSelectFirst: false, | |
|
738 | 804 | formatResult: autocompleteMainFilterFormatResult, |
|
739 | 805 | lookupFilter: autocompleteMainFilterResult, |
|
740 | 806 | onSelect: function (element, suggestion) { |
@@ -753,6 +819,18 b'' | |||
|
753 | 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 | 834 | </script> |
|
757 | 835 | <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script> |
|
758 | 836 | </%def> |
@@ -7,7 +7,7 b" go_import_header = ''" | |||
|
7 | 7 | if hasattr(c, 'rhodecode_db_repo'): |
|
8 | 8 | c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type |
|
9 | 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 | 11 | c.template_context['repo_view_type'] = h.get_repo_view_type(request) |
|
12 | 12 | |
|
13 | 13 | if getattr(c, 'repo_group', None): |
@@ -29,6 +29,7 b" c.template_context['default_user'] = {" | |||
|
29 | 29 | c.template_context['search_context'] = { |
|
30 | 30 | 'repo_group_id': c.template_context.get('repo_group_id'), |
|
31 | 31 | 'repo_group_name': c.template_context.get('repo_group_name'), |
|
32 | 'repo_id': c.template_context.get('repo_id'), | |
|
32 | 33 | 'repo_name': c.template_context.get('repo_name'), |
|
33 | 34 | 'repo_view_type': c.template_context.get('repo_view_type'), |
|
34 | 35 | } |
@@ -37,9 +37,9 b'' | |||
|
37 | 37 | |
|
38 | 38 | <%def name="menu_bar_subnav()"> |
|
39 | 39 | %if c.repo_name: |
|
40 |
${self.repo_menu(active='s |
|
|
40 | ${self.repo_menu(active='summary')} | |
|
41 | 41 | %elif c.repo_group_name: |
|
42 |
${self.repo_group_menu(active=' |
|
|
42 | ${self.repo_group_menu(active='home')} | |
|
43 | 43 | %endif |
|
44 | 44 | </%def> |
|
45 | 45 |
General Comments 0
You need to be logged in to leave comments.
Login now