go-to search: updated logic of goto switcher
- when in repo group searcher are ordered by the entries in the group - support prefixes with spaces, eg file: PATTERN - new contextual search for groups/repos with mark token - better suggestions
This commit is contained in:
parent
19d24cd946
commit
6039839d53
8 changed files with 366 additions and 153 deletions
|
|
@ -33,7 +33,7 @@ from rhodecode.lib.index import searcher_from_config
|
|||
from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.model.db import (
|
||||
func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
|
||||
func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.scm import RepoGroupList, RepoList
|
||||
|
|
@ -105,21 +105,27 @@ class HomeView(BaseAppView):
|
|||
|
||||
return {'suggestions': _user_groups}
|
||||
|
||||
def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
|
||||
def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
|
||||
org_query = name_contains
|
||||
allowed_ids = self._rhodecode_user.repo_acl_ids(
|
||||
['repository.read', 'repository.write', 'repository.admin'],
|
||||
cache=False, name_filter=name_contains) or [-1]
|
||||
|
||||
query = Repository.query()\
|
||||
.order_by(func.length(Repository.repo_name))\
|
||||
.order_by(Repository.repo_name)\
|
||||
.filter(Repository.archived.isnot(true()))\
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(Repository.repo_id, allowed_ids)
|
||||
))
|
||||
|
||||
query = query.order_by(case(
|
||||
[
|
||||
(Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
|
||||
],
|
||||
))
|
||||
query = query.order_by(func.length(Repository.repo_name))
|
||||
query = query.order_by(Repository.repo_name)
|
||||
|
||||
if repo_type:
|
||||
query = query.filter(Repository.repo_type == repo_type)
|
||||
|
||||
|
|
@ -145,20 +151,26 @@ class HomeView(BaseAppView):
|
|||
}
|
||||
for obj in acl_iter]
|
||||
|
||||
def _get_repo_group_list(self, name_contains=None, limit=20):
|
||||
def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
|
||||
org_query = name_contains
|
||||
allowed_ids = self._rhodecode_user.repo_group_acl_ids(
|
||||
['group.read', 'group.write', 'group.admin'],
|
||||
cache=False, name_filter=name_contains) or [-1]
|
||||
|
||||
query = RepoGroup.query()\
|
||||
.order_by(func.length(RepoGroup.group_name))\
|
||||
.order_by(RepoGroup.group_name) \
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(RepoGroup.group_id, allowed_ids)
|
||||
))
|
||||
|
||||
query = query.order_by(case(
|
||||
[
|
||||
(RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
|
||||
],
|
||||
))
|
||||
query = query.order_by(func.length(RepoGroup.group_name))
|
||||
query = query.order_by(RepoGroup.group_name)
|
||||
|
||||
if name_contains:
|
||||
ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
|
||||
query = query.filter(
|
||||
|
|
@ -183,11 +195,17 @@ class HomeView(BaseAppView):
|
|||
def _get_user_list(self, name_contains=None, limit=20):
|
||||
org_query = name_contains
|
||||
if not name_contains:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if not allowed_user_search:
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
|
||||
if len(name_contains) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = name_contains[0]
|
||||
|
||||
query = User.query()\
|
||||
|
|
@ -207,22 +225,28 @@ class HomeView(BaseAppView):
|
|||
{
|
||||
'id': obj.user_id,
|
||||
'value': org_query,
|
||||
'value_display': obj.username,
|
||||
'value_display': 'user: `{}`'.format(obj.username),
|
||||
'type': 'user',
|
||||
'icon_link': h.gravatar_url(obj.email, 30),
|
||||
'url': h.route_path(
|
||||
'user_profile', username=obj.username)
|
||||
}
|
||||
for obj in acl_iter]
|
||||
for obj in acl_iter], True
|
||||
|
||||
def _get_user_groups_list(self, name_contains=None, limit=20):
|
||||
org_query = name_contains
|
||||
if not name_contains:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if not allowed_user_search:
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
|
||||
if len(name_contains) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = name_contains[0]
|
||||
|
||||
query = UserGroup.query()\
|
||||
|
|
@ -241,27 +265,34 @@ class HomeView(BaseAppView):
|
|||
{
|
||||
'id': obj.users_group_id,
|
||||
'value': org_query,
|
||||
'value_display': obj.users_group_name,
|
||||
'value_display': 'user_group: `{}`'.format(obj.users_group_name),
|
||||
'type': 'user_group',
|
||||
'url': h.route_path(
|
||||
'user_group_profile', user_group_name=obj.users_group_name)
|
||||
}
|
||||
for obj in acl_iter]
|
||||
for obj in acl_iter], True
|
||||
|
||||
def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
|
||||
repo_name = repo_group_name = None
|
||||
if repo:
|
||||
repo_name = repo.repo_name
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
def _get_hash_commit_list(self, auth_user, searcher, query):
|
||||
org_query = query
|
||||
if not query or len(query) < 3 or not searcher:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
|
||||
commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
|
||||
|
||||
if len(commit_hashes) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
commit_hash = commit_hashes[0]
|
||||
|
||||
result = searcher.search(
|
||||
'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
|
||||
raise_on_exc=False)
|
||||
repo_name, repo_group_name, raise_on_exc=False)
|
||||
|
||||
commits = []
|
||||
for entry in result['results']:
|
||||
|
|
@ -286,22 +317,29 @@ class HomeView(BaseAppView):
|
|||
}
|
||||
|
||||
commits.append(commit_entry)
|
||||
return commits
|
||||
return commits, True
|
||||
|
||||
def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
|
||||
repo_name = repo_group_name = None
|
||||
if repo:
|
||||
repo_name = repo.repo_name
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
def _get_path_list(self, auth_user, searcher, query):
|
||||
org_query = query
|
||||
if not query or len(query) < 3 or not searcher:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
paths_re = re.compile('(?:file:)(.{1,})').findall(query)
|
||||
paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
|
||||
if len(paths_re) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
file_path = paths_re[0]
|
||||
|
||||
search_path = searcher.escape_specials(file_path)
|
||||
result = searcher.search(
|
||||
'file.raw:*{}*'.format(search_path), 'path', auth_user,
|
||||
raise_on_exc=False)
|
||||
repo_name, repo_group_name, raise_on_exc=False)
|
||||
|
||||
files = []
|
||||
for entry in result['results']:
|
||||
|
|
@ -327,7 +365,7 @@ class HomeView(BaseAppView):
|
|||
}
|
||||
|
||||
files.append(file_entry)
|
||||
return files
|
||||
return files, True
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
|
|
@ -405,17 +443,15 @@ class HomeView(BaseAppView):
|
|||
qry = query
|
||||
return {'q': qry, 'type': 'content'}
|
||||
label = u'File search for `{}` in this repository.'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -10,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
file_qry = {
|
||||
'id': -10,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
# commits
|
||||
def query_modifier():
|
||||
|
|
@ -423,17 +459,22 @@ class HomeView(BaseAppView):
|
|||
return {'q': qry, 'type': 'commit'}
|
||||
|
||||
label = u'Commit search for `{}` in this repository.'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -20,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
commit_qry = {
|
||||
'id': -20,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
if repo_context in ['commit', 'changelog']:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
elif repo_context in ['files', 'summary']:
|
||||
queries.extend([file_qry, commit_qry])
|
||||
else:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
|
||||
elif is_es_6 and repo_group_name:
|
||||
# files
|
||||
|
|
@ -442,17 +483,15 @@ class HomeView(BaseAppView):
|
|||
return {'q': qry, 'type': 'content'}
|
||||
|
||||
label = u'File search for `{}` in this repository group'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -30,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
file_qry = {
|
||||
'id': -30,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
# commits
|
||||
def query_modifier():
|
||||
|
|
@ -460,18 +499,24 @@ class HomeView(BaseAppView):
|
|||
return {'q': qry, 'type': 'commit'}
|
||||
|
||||
label = u'Commit search for `{}` in this repository group'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -40,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
commit_qry = {
|
||||
'id': -40,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
if repo_context in ['commit', 'changelog']:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
elif repo_context in ['files', 'summary']:
|
||||
queries.extend([file_qry, commit_qry])
|
||||
else:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
|
||||
# Global, not scoped
|
||||
if not queries:
|
||||
queries.append(
|
||||
{
|
||||
|
|
@ -510,65 +555,107 @@ class HomeView(BaseAppView):
|
|||
if not query:
|
||||
return {'suggestions': res}
|
||||
|
||||
def no_match(name):
|
||||
return {
|
||||
'id': -1,
|
||||
'value': "",
|
||||
'value_display': name,
|
||||
'type': 'text',
|
||||
'url': ""
|
||||
}
|
||||
searcher = searcher_from_config(self.request.registry.settings)
|
||||
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
|
||||
res.append(_q)
|
||||
has_specialized_search = False
|
||||
|
||||
# set repo context
|
||||
repo = None
|
||||
repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
|
||||
if repo_id:
|
||||
repo = Repository.get(repo_id)
|
||||
|
||||
# set group context
|
||||
repo_group = None
|
||||
repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
|
||||
if repo_group_id:
|
||||
repo_group = RepoGroup.get(repo_group_id)
|
||||
composed_hint = '{}/{}'.format(repo_group.group_name, query)
|
||||
show_hint = not query.startswith(repo_group.group_name)
|
||||
if repo_group and show_hint:
|
||||
hint = u'Repository search inside: `{}`'.format(composed_hint)
|
||||
res.append({
|
||||
'id': -1,
|
||||
'value': composed_hint,
|
||||
'value_display': hint,
|
||||
'type': 'hint',
|
||||
'url': ""
|
||||
})
|
||||
prefix_match = False
|
||||
|
||||
repo_groups = self._get_repo_group_list(query)
|
||||
for serialized_repo_group in repo_groups:
|
||||
res.append(serialized_repo_group)
|
||||
# user: type search
|
||||
if not prefix_match:
|
||||
users, prefix_match = self._get_user_list(query)
|
||||
if users:
|
||||
has_specialized_search = True
|
||||
for serialized_user in users:
|
||||
res.append(serialized_user)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching users found'))
|
||||
|
||||
repos = self._get_repo_list(query)
|
||||
for serialized_repo in repos:
|
||||
res.append(serialized_repo)
|
||||
# user_group: type search
|
||||
if not prefix_match:
|
||||
user_groups, prefix_match = self._get_user_groups_list(query)
|
||||
if user_groups:
|
||||
has_specialized_search = True
|
||||
for serialized_user_group in user_groups:
|
||||
res.append(serialized_user_group)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching user groups found'))
|
||||
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if allowed_user_search:
|
||||
users = self._get_user_list(query)
|
||||
for serialized_user in users:
|
||||
res.append(serialized_user)
|
||||
|
||||
user_groups = self._get_user_groups_list(query)
|
||||
for serialized_user_group in user_groups:
|
||||
res.append(serialized_user_group)
|
||||
|
||||
commits = self._get_hash_commit_list(c.auth_user, searcher, query)
|
||||
if commits:
|
||||
unique_repos = collections.OrderedDict()
|
||||
for commit in commits:
|
||||
repo_name = commit['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(commit)
|
||||
|
||||
for repo, commits in unique_repos.items():
|
||||
# FTS commit: type search
|
||||
if not prefix_match:
|
||||
commits, prefix_match = self._get_hash_commit_list(
|
||||
c.auth_user, searcher, query, repo, repo_group)
|
||||
if commits:
|
||||
has_specialized_search = True
|
||||
unique_repos = collections.OrderedDict()
|
||||
for commit in commits:
|
||||
res.append(commit)
|
||||
repo_name = commit['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(commit)
|
||||
|
||||
paths = self._get_path_list(c.auth_user, searcher, query)
|
||||
if paths:
|
||||
unique_repos = collections.OrderedDict()
|
||||
for path in paths:
|
||||
repo_name = path['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(path)
|
||||
for _repo, commits in unique_repos.items():
|
||||
for commit in commits:
|
||||
res.append(commit)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching commits found'))
|
||||
|
||||
for repo, paths in unique_repos.items():
|
||||
# FTS file: type search
|
||||
if not prefix_match:
|
||||
paths, prefix_match = self._get_path_list(
|
||||
c.auth_user, searcher, query, repo, repo_group)
|
||||
if paths:
|
||||
has_specialized_search = True
|
||||
unique_repos = collections.OrderedDict()
|
||||
for path in paths:
|
||||
res.append(path)
|
||||
repo_name = path['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(path)
|
||||
|
||||
for repo, paths in unique_repos.items():
|
||||
for path in paths:
|
||||
res.append(path)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching files found'))
|
||||
|
||||
# main suggestions
|
||||
if not has_specialized_search:
|
||||
repo_group_name = ''
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
|
||||
res.append(_q)
|
||||
|
||||
repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
|
||||
for serialized_repo_group in repo_groups:
|
||||
res.append(serialized_repo_group)
|
||||
|
||||
repos = self._get_repo_list(query, repo_group_name=repo_group_name)
|
||||
for serialized_repo in repos:
|
||||
res.append(serialized_repo)
|
||||
|
||||
if not repos and not repo_groups:
|
||||
res.append(no_match('No matches found'))
|
||||
|
||||
return {'suggestions': res}
|
||||
|
||||
|
|
|
|||
|
|
@ -2037,6 +2037,6 @@ def get_repo_view_type(request):
|
|||
'repo_files': 'files',
|
||||
'repo_summary': 'summary',
|
||||
'repo_commit': 'commit'
|
||||
|
||||
}
|
||||
|
||||
return route_to_view_type.get(route_name)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ from sqlalchemy import (
|
|||
Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
|
||||
Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
|
||||
Text, Float, PickleType)
|
||||
from sqlalchemy.sql.expression import true, false
|
||||
from sqlalchemy.sql.expression import true, false, case
|
||||
from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
|
||||
from sqlalchemy.orm import (
|
||||
relationship, joinedload, class_mapper, validates, aliased)
|
||||
|
|
|
|||
|
|
@ -644,6 +644,40 @@ ul#context-pages {
|
|||
|
||||
.main_filter_input_box {
|
||||
display: inline-block;
|
||||
|
||||
.searchItems {
|
||||
display:flex;
|
||||
background: #666666;
|
||||
padding: 0px;
|
||||
|
||||
a {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.searchTag {
|
||||
line-height: 28px;
|
||||
padding: 0px 4px;
|
||||
|
||||
.tag {
|
||||
color: @nav-grey;
|
||||
border-color: @nav-grey;
|
||||
}
|
||||
}
|
||||
|
||||
.searchTagFilter {
|
||||
background-color: @grey3 !important;
|
||||
}
|
||||
|
||||
.searchTagHelp {
|
||||
background-color: @grey2 !important;
|
||||
}
|
||||
.searchTagHelp:hover {
|
||||
background-color: @grey2 !important;
|
||||
}
|
||||
.searchTagInput {
|
||||
background-color: @grey3 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main_filter_box {
|
||||
|
|
@ -667,7 +701,8 @@ ul#context-pages {
|
|||
color: @nav-grey;
|
||||
background: @grey3;
|
||||
min-height: 18px;
|
||||
|
||||
border:none;
|
||||
border-radius: 0;
|
||||
|
||||
&:active {
|
||||
color: @grey2 !important;
|
||||
|
|
|
|||
|
|
@ -528,7 +528,19 @@
|
|||
if ($.isFunction(serviceUrl)) {
|
||||
serviceUrl = serviceUrl.call(that.element, query);
|
||||
}
|
||||
cacheKey = serviceUrl + '?' + $.param(params || {});
|
||||
|
||||
var callParams = {};
|
||||
//make an evaluated copy of params
|
||||
$.each(params, function(index, value) {
|
||||
if($.isFunction(value)){
|
||||
callParams[index] = value();
|
||||
}
|
||||
else {
|
||||
callParams[index] = value;
|
||||
}
|
||||
});
|
||||
|
||||
cacheKey = serviceUrl + '?' + $.param(callParams);
|
||||
response = that.cachedResponse[cacheKey];
|
||||
}
|
||||
|
||||
|
|
@ -536,7 +548,7 @@
|
|||
that.suggestions = response.suggestions;
|
||||
that.suggest();
|
||||
} else if (!that.isBadQuery(query)) {
|
||||
if (options.onSearchStart.call(that.element, options.params) === false) {
|
||||
if (options.onSearchStart.call(that.element, params) === false) {
|
||||
return;
|
||||
}
|
||||
if (that.currentRequest) {
|
||||
|
|
|
|||
|
|
@ -233,7 +233,6 @@
|
|||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
|
||||
%if c.rhodecode_db_repo.repo_type in ['git','hg']:
|
||||
|
|
@ -338,7 +337,6 @@
|
|||
<div class="wrapper">
|
||||
<ul id="context-pages" class="navigation horizontal-list">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<li class="${is_active('options')}">
|
||||
<a class="menulink dropdown">
|
||||
|
|
@ -486,10 +484,35 @@
|
|||
<li>
|
||||
<div class="menulabel main_filter_box">
|
||||
<div class="main_filter_input_box">
|
||||
<input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
|
||||
</div>
|
||||
<div class="main_filter_help_box">
|
||||
<a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
|
||||
<ul class="searchItems">
|
||||
|
||||
% if c.template_context['search_context']['repo_id']:
|
||||
<li class="searchTag searchTagFilter searchTagHidable" >
|
||||
##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
|
||||
<span class="tag">
|
||||
This repo
|
||||
<a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
|
||||
</span>
|
||||
##</a>
|
||||
</li>
|
||||
% elif c.template_context['search_context']['repo_group_id']:
|
||||
<li class="searchTag searchTagFilter searchTagHidable">
|
||||
##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
|
||||
<span class="tag">
|
||||
This group
|
||||
<a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-delete"></i></a>
|
||||
</span>
|
||||
##</a>
|
||||
</li>
|
||||
% endif
|
||||
|
||||
<li class="searchTagInput">
|
||||
<input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
|
||||
</li>
|
||||
<li class="searchTag searchTagHelp">
|
||||
<a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -500,13 +523,21 @@
|
|||
|
||||
- Prefix query to allow special search:
|
||||
|
||||
user:admin, to search for usernames
|
||||
user:admin, to search for usernames, always global
|
||||
|
||||
user_group:devops, to search for user groups
|
||||
user_group:devops, to search for user groups, always global
|
||||
|
||||
commit:efced4, to search for commits
|
||||
commit:efced4, to search for commits, scoped to repositories or groups
|
||||
|
||||
file:models.py, to search for file paths
|
||||
file:models.py, to search for file paths, scoped to repositories or groups
|
||||
|
||||
% if c.template_context['search_context']['repo_id']:
|
||||
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>
|
||||
% elif c.template_context['search_context']['repo_group_id']:
|
||||
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>
|
||||
% else:
|
||||
For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
|
||||
% endif
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
|
@ -622,6 +653,22 @@
|
|||
}(result, escapeMarkup);
|
||||
};
|
||||
|
||||
var escapeRegExChars = function (value) {
|
||||
return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
};
|
||||
|
||||
var getRepoIcon = function(repo_type) {
|
||||
if (repo_type === 'hg') {
|
||||
return '<i class="icon-hg"></i> ';
|
||||
}
|
||||
else if (repo_type === 'git') {
|
||||
return '<i class="icon-git"></i> ';
|
||||
}
|
||||
else if (repo_type === 'svn') {
|
||||
return '<i class="icon-svn"></i> ';
|
||||
}
|
||||
return ''
|
||||
};
|
||||
|
||||
var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
|
||||
|
||||
|
|
@ -632,27 +679,14 @@
|
|||
var searchType = data['type'];
|
||||
var valueDisplay = data['value_display'];
|
||||
|
||||
var escapeRegExChars = function (value) {
|
||||
return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
};
|
||||
var pattern = '(' + escapeRegExChars(value) + ')';
|
||||
|
||||
var getRepoIcon = function(repo_type) {
|
||||
if (repo_type === 'hg') {
|
||||
return '<i class="icon-hg"></i> ';
|
||||
}
|
||||
else if (repo_type === 'git') {
|
||||
return '<i class="icon-git"></i> ';
|
||||
}
|
||||
else if (repo_type === 'svn') {
|
||||
return '<i class="icon-svn"></i> ';
|
||||
}
|
||||
return ''
|
||||
};
|
||||
valueDisplay = Select2.util.escapeMarkup(valueDisplay);
|
||||
|
||||
// highlight match
|
||||
valueDisplay = Select2.util.escapeMarkup(valueDisplay);
|
||||
valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
|
||||
if (searchType != 'text') {
|
||||
valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
|
||||
}
|
||||
|
||||
var icon = '';
|
||||
|
||||
|
|
@ -684,6 +718,7 @@
|
|||
else if (searchType === 'user_group') {
|
||||
icon += '<i class="icon-group"></i> ';
|
||||
}
|
||||
// user
|
||||
else if (searchType === 'user') {
|
||||
icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
|
||||
}
|
||||
|
|
@ -707,6 +742,10 @@
|
|||
icon += '<i class="icon-tag"></i>';
|
||||
}
|
||||
}
|
||||
// generic text
|
||||
else if (searchType === 'text') {
|
||||
icon = '';
|
||||
}
|
||||
|
||||
var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
|
||||
return tmpl.format(icon, valueDisplay);
|
||||
|
|
@ -716,25 +755,52 @@
|
|||
if (suggestion.type === "hint") {
|
||||
// we skip action
|
||||
$('#main_filter').focus();
|
||||
}
|
||||
else if (suggestion.type === "text") {
|
||||
// we skip action
|
||||
$('#main_filter').focus();
|
||||
|
||||
} else {
|
||||
window.location = suggestion['url'];
|
||||
}
|
||||
};
|
||||
|
||||
var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
|
||||
if (queryLowerCase.split(':').length === 2) {
|
||||
queryLowerCase = queryLowerCase.split(':')[1]
|
||||
}
|
||||
if (suggestion.type === "text") {
|
||||
// special case we don't want to "skip" display for
|
||||
return true
|
||||
}
|
||||
return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
|
||||
};
|
||||
|
||||
var cleanContext = {
|
||||
repo_view_type: null,
|
||||
|
||||
repo_id: null,
|
||||
repo_name: "",
|
||||
|
||||
repo_group_id: null,
|
||||
repo_group_name: null
|
||||
};
|
||||
var removeGoToFilter = function () {
|
||||
$('.searchTagHidable').hide();
|
||||
$('#main_filter').autocomplete(
|
||||
'setOptions', {params:{search_context: cleanContext}});
|
||||
};
|
||||
|
||||
$('#main_filter').autocomplete({
|
||||
serviceUrl: pyroutes.url('goto_switcher_data'),
|
||||
params: {"search_context": templateContext.search_context},
|
||||
params: {
|
||||
"search_context": templateContext.search_context
|
||||
},
|
||||
minChars:2,
|
||||
maxHeight:400,
|
||||
deferRequestBy: 300, //miliseconds
|
||||
tabDisabled: true,
|
||||
autoSelectFirst: true,
|
||||
autoSelectFirst: false,
|
||||
formatResult: autocompleteMainFilterFormatResult,
|
||||
lookupFilter: autocompleteMainFilterResult,
|
||||
onSelect: function (element, suggestion) {
|
||||
|
|
@ -753,6 +819,18 @@
|
|||
$('#main_filter_help').toggle();
|
||||
};
|
||||
|
||||
$('#main_filter').on('keydown.autocomplete', function (e) {
|
||||
|
||||
var BACKSPACE = 8;
|
||||
var el = $(e.currentTarget);
|
||||
if(e.which === BACKSPACE){
|
||||
var inputVal = el.val();
|
||||
if (inputVal === ""){
|
||||
removeGoToFilter()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
|
||||
</%def>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ go_import_header = ''
|
|||
if hasattr(c, 'rhodecode_db_repo'):
|
||||
c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
|
||||
c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
|
||||
## check repo context
|
||||
c.template_context['repo_id'] = c.rhodecode_db_repo.repo_id
|
||||
c.template_context['repo_view_type'] = h.get_repo_view_type(request)
|
||||
|
||||
if getattr(c, 'repo_group', None):
|
||||
|
|
@ -29,6 +29,7 @@ c.template_context['default_user'] = {
|
|||
c.template_context['search_context'] = {
|
||||
'repo_group_id': c.template_context.get('repo_group_id'),
|
||||
'repo_group_name': c.template_context.get('repo_group_name'),
|
||||
'repo_id': c.template_context.get('repo_id'),
|
||||
'repo_name': c.template_context.get('repo_name'),
|
||||
'repo_view_type': c.template_context.get('repo_view_type'),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@
|
|||
|
||||
<%def name="menu_bar_subnav()">
|
||||
%if c.repo_name:
|
||||
${self.repo_menu(active='search')}
|
||||
${self.repo_menu(active='summary')}
|
||||
%elif c.repo_group_name:
|
||||
${self.repo_group_menu(active='search')}
|
||||
${self.repo_group_menu(active='home')}
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue