##// END OF EJS Templates
search: allow result sorting for elasticsearch6
marcink -
r3963:107ed32f default
parent child Browse files
Show More
@@ -44,6 +44,7 b' def perform_search(request, tmpl_context'
44 search_tags = []
44 search_tags = []
45 search_params = {}
45 search_params = {}
46 errors = []
46 errors = []
47
47 try:
48 try:
48 search_params = schema.deserialize(
49 search_params = schema.deserialize(
49 dict(
50 dict(
@@ -61,8 +62,8 b' def perform_search(request, tmpl_context'
61 def url_generator(**kw):
62 def url_generator(**kw):
62 q = urllib.quote(safe_str(search_query))
63 q = urllib.quote(safe_str(search_query))
63 return update_params(
64 return update_params(
64 "?q=%s&type=%s&max_lines=%s" % (
65 "?q=%s&type=%s&max_lines=%s&sort=%s" % (
65 q, safe_str(search_type), search_max_lines), **kw)
66 q, safe_str(search_type), search_max_lines, search_sort), **kw)
66
67
67 c = tmpl_context
68 c = tmpl_context
68 search_query = search_params.get('search_query')
69 search_query = search_params.get('search_query')
@@ -99,7 +100,6 b' def perform_search(request, tmpl_context'
99 c.perm_user = c.auth_user
100 c.perm_user = c.auth_user
100 c.repo_name = repo_name
101 c.repo_name = repo_name
101 c.repo_group_name = repo_group_name
102 c.repo_group_name = repo_group_name
102 c.sort = search_sort
103 c.url_generator = url_generator
103 c.url_generator = url_generator
104 c.errors = errors
104 c.errors = errors
105 c.formatted_results = formatted_results
105 c.formatted_results = formatted_results
@@ -109,6 +109,11 b' def perform_search(request, tmpl_context'
109 c.searcher = searcher
109 c.searcher = searcher
110 c.search_tags = search_tags
110 c.search_tags = search_tags
111
111
112 direction, sort_field = searcher.get_sort(search_type, search_sort)
113 c.sort = '{}:{}'.format(direction, sort_field)
114 c.sort_tag = sort_field
115 c.sort_tag_dir = direction
116
112
117
113 class SearchView(BaseAppView):
118 class SearchView(BaseAppView):
114 def load_default_context(self):
119 def load_default_context(self):
@@ -46,6 +46,8 b' class BaseSearcher(object):'
46 query_lang_doc = ''
46 query_lang_doc = ''
47 es_version = None
47 es_version = None
48 name = None
48 name = None
49 DIRECTION_ASC = 'asc'
50 DIRECTION_DESC = 'desc'
49
51
50 def __init__(self):
52 def __init__(self):
51 pass
53 pass
@@ -87,6 +89,37 b' class BaseSearcher(object):'
87 """
89 """
88 return val
90 return val
89
91
92 @staticmethod
93 def get_sort(search_type, search_val):
94 """
95 Method used to parse the GET search sort value to a field and direction.
96 e.g asc:lines == asc, lines
97
98 There's also a legacy support for newfirst/oldfirst which defines commit
99 sorting only
100 """
101
102 direction = BaseSearcher.DIRECTION_ASC
103 sort_field = None
104
105 if not search_val:
106 return direction, sort_field
107
108 if search_val.startswith('asc:'):
109 sort_field = search_val[4:]
110 direction = BaseSearcher.DIRECTION_ASC
111 elif search_val.startswith('desc:'):
112 sort_field = search_val[5:]
113 direction = BaseSearcher.DIRECTION_DESC
114 elif search_val == 'newfirst' and search_type == 'commit':
115 sort_field = 'date'
116 direction = BaseSearcher.DIRECTION_DESC
117 elif search_val == 'oldfirst' and search_type == 'commit':
118 sort_field = 'date'
119 direction = BaseSearcher.DIRECTION_ASC
120
121 return direction, sort_field
122
90
123
91 def search_config(config, prefix='search.'):
124 def search_config(config, prefix='search.'):
92 _config = {}
125 _config = {}
@@ -22,6 +22,18 b''
22 import colander
22 import colander
23
23
24
24
25 def sort_validator(node, value):
26 if value in ['oldfirst', 'newfirst']:
27 return value
28 if value.startswith('asc:'):
29 return value
30 if value.startswith('desc:'):
31 return value
32
33 msg = u'Invalid search sort, must be `oldfirst`, `newfirst`, or start with asc: or desc:'
34 raise colander.Invalid(node, msg)
35
36
25 class SearchParamsSchema(colander.MappingSchema):
37 class SearchParamsSchema(colander.MappingSchema):
26 search_query = colander.SchemaNode(
38 search_query = colander.SchemaNode(
27 colander.String(),
39 colander.String(),
@@ -33,7 +45,7 b' class SearchParamsSchema(colander.Mappin'
33 search_sort = colander.SchemaNode(
45 search_sort = colander.SchemaNode(
34 colander.String(),
46 colander.String(),
35 missing='newfirst',
47 missing='newfirst',
36 validator=colander.OneOf(['oldfirst', 'newfirst']))
48 validator=sort_validator)
37 search_max_lines = colander.SchemaNode(
49 search_max_lines = colander.SchemaNode(
38 colander.Integer(),
50 colander.Integer(),
39 missing=10)
51 missing=10)
@@ -60,6 +60,20 b''
60 <i class="icon-repo-group"></i>
60 <i class="icon-repo-group"></i>
61 </%def>
61 </%def>
62
62
63
64 <%def name="field_sort(field_name)">
65
66 <%
67 if c.sort.startswith('asc:'):
68 return c.url_generator(sort='desc:{}'.format(field_name))
69 elif c.sort.startswith('desc:'):
70 return c.url_generator(sort='asc:{}'.format(field_name))
71
72 return 'asc:{}'.format(field_name)
73 %>
74 </%def>
75
76
63 <%def name="main()">
77 <%def name="main()">
64 <div class="box">
78 <div class="box">
65 %if c.repo_name:
79 %if c.repo_name:
@@ -114,6 +128,16 b''
114 </span>
128 </span>
115 %endif
129 %endif
116
130
131 % if c.sort_tag:
132 <span class="tag tag8">
133 % if c.sort_tag_dir == 'asc':
134 <i class="icon-angle-down"></i>
135 % elif c.sort_tag_dir == 'desc':
136 <i class="icon-angle-up"></i>
137 % endif
138 ${_('sort')}:${c.sort_tag}
139 </span>
140 % endif
117
141
118 % for search_tag in c.search_tags:
142 % for search_tag in c.search_tags:
119 <br/><span class="tag disabled" style="margin-top: 3px">${search_tag}</span>
143 <br/><span class="tag disabled" style="margin-top: 3px">${search_tag}</span>
@@ -130,7 +154,7 b''
130 </span>
154 </span>
131 % endfor
155 % endfor
132 <div class="field">
156 <div class="field">
133 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Query Langague examples')}</p>
157 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Query Language examples')}</p>
134 <pre id="search-help" style="display: none">\
158 <pre id="search-help" style="display: none">\
135
159
136 % if c.searcher.name == 'whoosh':
160 % if c.searcher.name == 'whoosh':
@@ -8,15 +8,15 b''
8 <th>${_('Repository')}</th>
8 <th>${_('Repository')}</th>
9 <th>${_('Commit')}</th>
9 <th>${_('Commit')}</th>
10 <th></th>
10 <th></th>
11 <th>${_('Commit message')}</th>
11 <th>
12 <a href="${search.field_sort('message.raw')}">${_('Commit message')}</a>
13 </th>
12 <th>
14 <th>
13 %if c.sort == 'newfirst':
15 <a href="${search.field_sort('date')}">${_('Age')}</a>
14 <a href="${c.url_generator(sort='oldfirst')}">${_('Age (new first)')}</a>
15 %else:
16 <a href="${c.url_generator(sort='newfirst')}">${_('Age (old first)')}</a>
17 %endif
18 </th>
16 </th>
19 <th>${_('Author')}</th>
17 <th>
18 <a href="${search.field_sort('author.email.raw')}">${_('Author')}</a>
19 </th>
20 </tr>
20 </tr>
21 %for entry in c.formatted_results:
21 %for entry in c.formatted_results:
22 ## search results are additionally filtered, and this check is just a safe gate
22 ## search results are additionally filtered, and this check is just a safe gate
@@ -5,9 +5,15 b''
5 <table class="rctable search-results">
5 <table class="rctable search-results">
6 <tr>
6 <tr>
7 <th>${_('Repository')}</th>
7 <th>${_('Repository')}</th>
8 <th>${_('File')}</th>
8 <th>
9 <th>${_('Size')}</th>
9 <a href="${search.field_sort('file.raw')}">${_('File')}</a>
10 <th>${_('Lines')}</th>
10 </th>
11 <th>
12 <a href="${search.field_sort('size')}">${_('Size')}</a>
13 </th>
14 <th>
15 <a href="${search.field_sort('lines')}">${_('Lines')}</a>
16 </th>
11 </tr>
17 </tr>
12 %for entry in c.formatted_results:
18 %for entry in c.formatted_results:
13 ## search results are additionally filtered, and this check is just a safe gate
19 ## search results are additionally filtered, and this check is just a safe gate
@@ -19,6 +25,7 b''
19 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
25 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
20 </td>
26 </td>
21 <td class="td-componentname">
27 <td class="td-componentname">
28 <i class="icon-file"></i>
22 ${h.link_to(h.literal(entry['f_path']),
29 ${h.link_to(h.literal(entry['f_path']),
23 h.route_path('repo_files',repo_name=entry['repository'],commit_id='tip',f_path=entry['f_path']))}
30 h.route_path('repo_files',repo_name=entry['repository'],commit_id='tip',f_path=entry['f_path']))}
24 </td>
31 </td>
@@ -29,7 +36,7 b''
29 </td>
36 </td>
30 <td>
37 <td>
31 %if entry.get('lines'):
38 %if entry.get('lines'):
32 ${entry.get('lines', 0.)} ${_ungettext('line', 'lines', entry.get('lines', 0.))}
39 ${entry.get('lines', 0.)}
33 %endif
40 %endif
34 </td>
41 </td>
35 </tr>
42 </tr>
General Comments 0
You need to be logged in to leave comments. Login now