Show More
@@ -19,22 +19,44 b'' | |||
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | |
|
22 | def assert_and_get_content(result): | |
|
22 | def assert_and_get_main_filter_content(result): | |
|
23 | 23 | repos = [] |
|
24 | 24 | groups = [] |
|
25 | 25 | commits = [] |
|
26 | users = [] | |
|
27 | for data_item in result: | |
|
28 | assert data_item['id'] | |
|
29 | assert data_item['value'] | |
|
30 | assert data_item['value_display'] | |
|
31 | assert data_item['url'] | |
|
32 | ||
|
33 | if data_item['type'] == 'search': | |
|
34 | assert data_item['value_display'].startswith('Full text search for:') | |
|
35 | elif data_item['type'] == 'repo': | |
|
36 | repos.append(data_item) | |
|
37 | elif data_item['type'] == 'repo_group': | |
|
38 | groups.append(data_item) | |
|
39 | elif data_item['type'] == 'user': | |
|
40 | users.append(data_item) | |
|
41 | elif data_item['type'] == 'commit': | |
|
42 | commits.append(data_item) | |
|
43 | else: | |
|
44 | raise Exception('invalid type `%s`' % data_item['type']) | |
|
45 | ||
|
46 | return repos, groups, users, commits | |
|
47 | ||
|
48 | ||
|
49 | def assert_and_get_repo_list_content(result): | |
|
50 | repos = [] | |
|
26 | 51 | for data in result: |
|
27 | 52 | for data_item in data['children']: |
|
28 | 53 | assert data_item['id'] |
|
29 | 54 | assert data_item['text'] |
|
30 | 55 | assert data_item['url'] |
|
56 | ||
|
31 | 57 | if data_item['type'] == 'repo': |
|
32 | 58 | repos.append(data_item) |
|
33 | elif data_item['type'] == 'group': | |
|
34 | groups.append(data_item) | |
|
35 | elif data_item['type'] == 'commit': | |
|
36 | commits.append(data_item) | |
|
37 | 59 | else: |
|
38 | 60 | raise Exception('invalid type %s' % data_item['type']) |
|
39 | 61 | |
|
40 |
return repos |
|
|
62 | return repos |
@@ -22,7 +22,7 b' import json' | |||
|
22 | 22 | |
|
23 | 23 | import pytest |
|
24 | 24 | |
|
25 | from . import assert_and_get_content | |
|
25 | from . import assert_and_get_main_filter_content | |
|
26 | 26 | from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN |
|
27 | 27 | from rhodecode.tests.fixture import Fixture |
|
28 | 28 | |
@@ -103,19 +103,15 b' class TestGotoSwitcherData(TestControlle' | |||
|
103 | 103 | RepoGroupModel().delete(el, force_delete=True) |
|
104 | 104 | Session().commit() |
|
105 | 105 | |
|
106 |
def test_ |
|
|
106 | def test_empty_query(self, xhr_header): | |
|
107 | 107 | self.log_user() |
|
108 | 108 | |
|
109 | 109 | response = self.app.get( |
|
110 | 110 | route_path('goto_switcher_data'), |
|
111 | 111 | extra_environ=xhr_header, status=200) |
|
112 |
result = json.loads(response.body)[' |
|
|
113 | ||
|
114 | repos, groups, commits = assert_and_get_content(result) | |
|
112 | result = json.loads(response.body)['suggestions'] | |
|
115 | 113 | |
|
116 | assert len(repos) == len(Repository.get_all()) | |
|
117 | assert len(groups) == len(RepoGroup.get_all()) | |
|
118 | assert len(commits) == 0 | |
|
114 | assert result == [] | |
|
119 | 115 | |
|
120 | 116 | def test_returns_list_of_repos_and_groups_filtered(self, xhr_header): |
|
121 | 117 | self.log_user() |
@@ -124,14 +120,47 b' class TestGotoSwitcherData(TestControlle' | |||
|
124 | 120 | route_path('goto_switcher_data'), |
|
125 | 121 | params={'query': 'abc'}, |
|
126 | 122 | extra_environ=xhr_header, status=200) |
|
127 |
result = json.loads(response.body)[' |
|
|
123 | result = json.loads(response.body)['suggestions'] | |
|
128 | 124 | |
|
129 | repos, groups, commits = assert_and_get_content(result) | |
|
125 | repos, groups, users, commits = assert_and_get_main_filter_content(result) | |
|
130 | 126 | |
|
131 | 127 | assert len(repos) == 13 |
|
132 | 128 | assert len(groups) == 5 |
|
129 | assert len(users) == 0 | |
|
133 | 130 | assert len(commits) == 0 |
|
134 | 131 | |
|
132 | def test_returns_list_of_users_filtered(self, xhr_header): | |
|
133 | self.log_user() | |
|
134 | ||
|
135 | response = self.app.get( | |
|
136 | route_path('goto_switcher_data'), | |
|
137 | params={'query': 'user:admin'}, | |
|
138 | extra_environ=xhr_header, status=200) | |
|
139 | result = json.loads(response.body)['suggestions'] | |
|
140 | ||
|
141 | repos, groups, users, commits = assert_and_get_main_filter_content(result) | |
|
142 | ||
|
143 | assert len(repos) == 0 | |
|
144 | assert len(groups) == 0 | |
|
145 | assert len(users) == 1 | |
|
146 | assert len(commits) == 0 | |
|
147 | ||
|
148 | def test_returns_list_of_commits_filtered(self, xhr_header): | |
|
149 | self.log_user() | |
|
150 | ||
|
151 | response = self.app.get( | |
|
152 | route_path('goto_switcher_data'), | |
|
153 | params={'query': 'commit:e8'}, | |
|
154 | extra_environ=xhr_header, status=200) | |
|
155 | result = json.loads(response.body)['suggestions'] | |
|
156 | ||
|
157 | repos, groups, users, commits = assert_and_get_main_filter_content(result) | |
|
158 | ||
|
159 | assert len(repos) == 0 | |
|
160 | assert len(groups) == 0 | |
|
161 | assert len(users) == 0 | |
|
162 | assert len(commits) == 5 | |
|
163 | ||
|
135 | 164 | def test_returns_list_of_properly_sorted_and_filtered(self, xhr_header): |
|
136 | 165 | self.log_user() |
|
137 | 166 | |
@@ -139,13 +168,13 b' class TestGotoSwitcherData(TestControlle' | |||
|
139 | 168 | route_path('goto_switcher_data'), |
|
140 | 169 | params={'query': 'abc'}, |
|
141 | 170 | extra_environ=xhr_header, status=200) |
|
142 |
result = json.loads(response.body)[' |
|
|
171 | result = json.loads(response.body)['suggestions'] | |
|
143 | 172 | |
|
144 | repos, groups, commits = assert_and_get_content(result) | |
|
173 | repos, groups, users, commits = assert_and_get_main_filter_content(result) | |
|
145 | 174 | |
|
146 |
test_repos = [x[' |
|
|
175 | test_repos = [x['value_display'] for x in repos[:4]] | |
|
147 | 176 | assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos |
|
148 | 177 | |
|
149 |
test_groups = [x[' |
|
|
178 | test_groups = [x['value_display'] for x in groups[:4]] | |
|
150 | 179 | assert ['abc_repos', 'repos_abc', |
|
151 | 180 | 'forked-abc', 'forked-abc/a'] == test_groups |
@@ -20,7 +20,7 b'' | |||
|
20 | 20 | |
|
21 | 21 | import json |
|
22 | 22 | |
|
23 | from . import assert_and_get_content | |
|
23 | from . import assert_and_get_repo_list_content | |
|
24 | 24 | from rhodecode.tests import TestController |
|
25 | 25 | from rhodecode.tests.fixture import Fixture |
|
26 | 26 | from rhodecode.model.db import Repository |
@@ -50,11 +50,9 b' class TestRepoListData(TestController):' | |||
|
50 | 50 | extra_environ=xhr_header, status=200) |
|
51 | 51 | result = json.loads(response.body)['results'] |
|
52 | 52 | |
|
53 |
repos |
|
|
53 | repos = assert_and_get_repo_list_content(result) | |
|
54 | 54 | |
|
55 | 55 | assert len(repos) == len(Repository.get_all()) |
|
56 | assert len(groups) == 0 | |
|
57 | assert len(commits) == 0 | |
|
58 | 56 | |
|
59 | 57 | def test_returns_list_of_repos_and_groups_filtered(self, xhr_header): |
|
60 | 58 | self.log_user() |
@@ -65,12 +63,10 b' class TestRepoListData(TestController):' | |||
|
65 | 63 | extra_environ=xhr_header, status=200) |
|
66 | 64 | result = json.loads(response.body)['results'] |
|
67 | 65 | |
|
68 |
repos |
|
|
66 | repos = assert_and_get_repo_list_content(result) | |
|
69 | 67 | |
|
70 | 68 | assert len(repos) == len(Repository.query().filter( |
|
71 | 69 | Repository.repo_name.ilike('%vcs_test_git%')).all()) |
|
72 | assert len(groups) == 0 | |
|
73 | assert len(commits) == 0 | |
|
74 | 70 | |
|
75 | 71 | def test_returns_list_of_repos_and_groups_filtered_with_type(self, xhr_header): |
|
76 | 72 | self.log_user() |
@@ -81,12 +77,10 b' class TestRepoListData(TestController):' | |||
|
81 | 77 | extra_environ=xhr_header, status=200) |
|
82 | 78 | result = json.loads(response.body)['results'] |
|
83 | 79 | |
|
84 |
repos |
|
|
80 | repos = assert_and_get_repo_list_content(result) | |
|
85 | 81 | |
|
86 | 82 | assert len(repos) == len(Repository.query().filter( |
|
87 | 83 | Repository.repo_name.ilike('%vcs_test_git%')).all()) |
|
88 | assert len(groups) == 0 | |
|
89 | assert len(commits) == 0 | |
|
90 | 84 | |
|
91 | 85 | def test_returns_list_of_repos_non_ascii_query(self, xhr_header): |
|
92 | 86 | self.log_user() |
@@ -96,8 +90,6 b' class TestRepoListData(TestController):' | |||
|
96 | 90 | extra_environ=xhr_header, status=200) |
|
97 | 91 | result = json.loads(response.body)['results'] |
|
98 | 92 | |
|
99 |
repos |
|
|
93 | repos = assert_and_get_repo_list_content(result) | |
|
100 | 94 | |
|
101 | 95 | assert len(repos) == 0 |
|
102 | assert len(groups) == 0 | |
|
103 | assert len(commits) == 0 |
@@ -20,6 +20,7 b'' | |||
|
20 | 20 | |
|
21 | 21 | import re |
|
22 | 22 | import logging |
|
23 | import collections | |
|
23 | 24 | |
|
24 | 25 | from pyramid.view import view_config |
|
25 | 26 | |
@@ -31,7 +32,7 b' from rhodecode.lib.index import searcher' | |||
|
31 | 32 | from rhodecode.lib.utils2 import safe_unicode, str2bool |
|
32 | 33 | from rhodecode.lib.ext_json import json |
|
33 | 34 | from rhodecode.model.db import ( |
|
34 | func, or_, in_filter_generator, Repository, RepoGroup) | |
|
35 | func, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup) | |
|
35 | 36 | from rhodecode.model.repo import RepoModel |
|
36 | 37 | from rhodecode.model.repo_group import RepoGroupModel |
|
37 | 38 | from rhodecode.model.scm import RepoGroupList, RepoList |
@@ -104,6 +105,7 b' class HomeView(BaseAppView):' | |||
|
104 | 105 | return {'suggestions': _user_groups} |
|
105 | 106 | |
|
106 | 107 | def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): |
|
108 | org_query = name_contains | |
|
107 | 109 | allowed_ids = self._rhodecode_user.repo_acl_ids( |
|
108 | 110 | ['repository.read', 'repository.write', 'repository.admin'], |
|
109 | 111 | cache=False, name_filter=name_contains) or [-1] |
@@ -125,20 +127,24 b' class HomeView(BaseAppView):' | |||
|
125 | 127 | Repository.repo_name.ilike(ilike_expression)) |
|
126 | 128 | query = query.limit(limit) |
|
127 | 129 | |
|
128 |
acl_ |
|
|
130 | acl_iter = query | |
|
129 | 131 | |
|
130 | 132 | return [ |
|
131 | 133 | { |
|
132 | 134 | 'id': obj.repo_name, |
|
135 | 'value': org_query, | |
|
136 | 'value_display': obj.repo_name, | |
|
133 | 137 | 'text': obj.repo_name, |
|
134 | 138 | 'type': 'repo', |
|
135 |
' |
|
|
136 |
|
|
|
139 | 'repo_id': obj.repo_id, | |
|
140 | 'repo_type': obj.repo_type, | |
|
141 | 'private': obj.private, | |
|
137 | 142 | 'url': h.route_path('repo_summary', repo_name=obj.repo_name) |
|
138 | 143 | } |
|
139 |
for obj in acl_ |
|
|
144 | for obj in acl_iter] | |
|
140 | 145 | |
|
141 | 146 | def _get_repo_group_list(self, name_contains=None, limit=20): |
|
147 | org_query = name_contains | |
|
142 | 148 | allowed_ids = self._rhodecode_user.repo_group_acl_ids( |
|
143 | 149 | ['group.read', 'group.write', 'group.admin'], |
|
144 | 150 | cache=False, name_filter=name_contains) or [-1] |
@@ -157,20 +163,56 b' class HomeView(BaseAppView):' | |||
|
157 | 163 | RepoGroup.group_name.ilike(ilike_expression)) |
|
158 | 164 | query = query.limit(limit) |
|
159 | 165 | |
|
160 |
acl_ |
|
|
166 | acl_iter = query | |
|
161 | 167 | |
|
162 | 168 | return [ |
|
163 | 169 | { |
|
164 | 170 | 'id': obj.group_name, |
|
165 |
' |
|
|
166 |
' |
|
|
167 |
' |
|
|
171 | 'value': org_query, | |
|
172 | 'value_display': obj.group_name, | |
|
173 | 'type': 'repo_group', | |
|
168 | 174 | 'url': h.route_path( |
|
169 | 175 | 'repo_group_home', repo_group_name=obj.group_name) |
|
170 | 176 | } |
|
171 |
for obj in acl_ |
|
|
177 | for obj in acl_iter] | |
|
178 | ||
|
179 | def _get_user_list(self, name_contains=None, limit=20): | |
|
180 | org_query = name_contains | |
|
181 | if not name_contains: | |
|
182 | return [] | |
|
183 | ||
|
184 | name_contains = re.compile('(?:user:)(.+)').findall(name_contains) | |
|
185 | if len(name_contains) != 1: | |
|
186 | return [] | |
|
187 | name_contains = name_contains[0] | |
|
188 | ||
|
189 | query = User.query()\ | |
|
190 | .order_by(func.length(User.username))\ | |
|
191 | .order_by(User.username) \ | |
|
192 | .filter(User.username != User.DEFAULT_USER) | |
|
172 | 193 | |
|
173 | def _get_hash_commit_list(self, auth_user, query=None): | |
|
194 | if name_contains: | |
|
195 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) | |
|
196 | query = query.filter( | |
|
197 | User.username.ilike(ilike_expression)) | |
|
198 | query = query.limit(limit) | |
|
199 | ||
|
200 | acl_iter = query | |
|
201 | ||
|
202 | return [ | |
|
203 | { | |
|
204 | 'id': obj.user_id, | |
|
205 | 'value': org_query, | |
|
206 | 'value_display': obj.username, | |
|
207 | 'type': 'user', | |
|
208 | 'icon_link': h.gravatar_url(obj.email, 30), | |
|
209 | 'url': h.route_path( | |
|
210 | 'user_profile', username=obj.username) | |
|
211 | } | |
|
212 | for obj in acl_iter] | |
|
213 | ||
|
214 | def _get_hash_commit_list(self, auth_user, query): | |
|
215 | org_query = query | |
|
174 | 216 | if not query or len(query) < 3: |
|
175 | 217 | return [] |
|
176 | 218 | |
@@ -178,20 +220,21 b' class HomeView(BaseAppView):' | |||
|
178 | 220 | |
|
179 | 221 | if len(commit_hashes) != 1: |
|
180 | 222 | return [] |
|
181 | ||
|
182 | commit_hash_prefix = commit_hashes[0] | |
|
223 | commit_hash = commit_hashes[0] | |
|
183 | 224 | |
|
184 | 225 | searcher = searcher_from_config(self.request.registry.settings) |
|
185 | 226 | result = searcher.search( |
|
186 |
'commit_id:%s*' % commit_hash |
|
|
227 | 'commit_id:%s*' % commit_hash, 'commit', auth_user, | |
|
187 | 228 | raise_on_exc=False) |
|
188 | 229 | |
|
189 | 230 | return [ |
|
190 | 231 | { |
|
191 | 232 | 'id': entry['commit_id'], |
|
192 |
' |
|
|
233 | 'value': org_query, | |
|
234 | 'value_display': 'repo `{}` commit: {}'.format( | |
|
235 | entry['repository'], entry['commit_id']), | |
|
193 | 236 | 'type': 'commit', |
|
194 |
|
|
|
237 | 'repo': entry['repository'], | |
|
195 | 238 | 'url': h.route_path( |
|
196 | 239 | 'repo_commit', |
|
197 | 240 | repo_name=entry['repository'], commit_id=entry['commit_id']) |
@@ -235,41 +278,47 b' class HomeView(BaseAppView):' | |||
|
235 | 278 | _ = self.request.translate |
|
236 | 279 | |
|
237 | 280 | query = self.request.GET.get('query') |
|
238 |
log.debug('generating |
|
|
281 | log.debug('generating main filter data, query %s', query) | |
|
282 | ||
|
283 | default_search_val = 'Full text search for: `{}`'.format(query) | |
|
284 | res = [] | |
|
285 | if not query: | |
|
286 | return {'suggestions': res} | |
|
239 | 287 | |
|
240 |
res |
|
|
288 | res.append({ | |
|
289 | 'id': -1, | |
|
290 | 'value': query, | |
|
291 | 'value_display': default_search_val, | |
|
292 | 'type': 'search', | |
|
293 | 'url': h.route_path( | |
|
294 | 'search', _query={'q': query}) | |
|
295 | }) | |
|
296 | ||
|
241 | 297 | repo_groups = self._get_repo_group_list(query) |
|
242 |
|
|
|
243 |
res.append( |
|
|
244 | 'text': _('Groups'), | |
|
245 | 'children': repo_groups | |
|
246 | }) | |
|
298 | for serialized_repo_group in repo_groups: | |
|
299 | res.append(serialized_repo_group) | |
|
247 | 300 | |
|
248 | 301 | repos = self._get_repo_list(query) |
|
249 | if repos: | |
|
250 |
res.append( |
|
|
251 | 'text': _('Repositories'), | |
|
252 | 'children': repos | |
|
253 | }) | |
|
302 | for serialized_repo in repos: | |
|
303 | res.append(serialized_repo) | |
|
304 | ||
|
305 | # TODO(marcink): permissions for that ? | |
|
306 | users = self._get_user_list(query) | |
|
307 | for serialized_user in users: | |
|
308 | res.append(serialized_user) | |
|
254 | 309 | |
|
255 | 310 | commits = self._get_hash_commit_list(c.auth_user, query) |
|
256 | 311 | if commits: |
|
257 |
unique_repos = |
|
|
312 | unique_repos = collections.OrderedDict() | |
|
258 | 313 | for commit in commits: |
|
259 |
|
|
|
260 |
|
|
|
314 | repo_name = commit['repo'] | |
|
315 | unique_repos.setdefault(repo_name, []).append(commit) | |
|
261 | 316 | |
|
262 | for repo in unique_repos: | |
|
263 | res.append({ | |
|
264 | 'text': _('Commits in %(repo)s') % {'repo': repo}, | |
|
265 | 'children': unique_repos[repo] | |
|
266 | }) | |
|
317 | for repo, commits in unique_repos.items(): | |
|
318 | for commit in commits: | |
|
319 | res.append(commit) | |
|
267 | 320 | |
|
268 | data = { | |
|
269 | 'more': False, | |
|
270 | 'results': res | |
|
271 | } | |
|
272 | return data | |
|
321 | return {'suggestions': res} | |
|
273 | 322 | |
|
274 | 323 | def _get_groups_and_repos(self, repo_group_id=None): |
|
275 | 324 | # repo groups groups |
@@ -766,7 +766,10 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
766 | 766 | 'id': obj['name'], |
|
767 | 767 | 'text': obj['name'], |
|
768 | 768 | 'type': 'repo', |
|
769 |
' |
|
|
769 | 'repo_id': obj['dbrepo']['repo_id'], | |
|
770 | 'repo_type': obj['dbrepo']['repo_type'], | |
|
771 | 'private': obj['dbrepo']['private'], | |
|
772 | ||
|
770 | 773 | }) |
|
771 | 774 | |
|
772 | 775 | data = { |
@@ -281,11 +281,9 b'' | |||
|
281 | 281 | } |
|
282 | 282 | |
|
283 | 283 | .navigation li.open { |
|
284 | ||
|
285 | .submenu, | |
|
286 | .repo_switcher { | |
|
287 | display: block; | |
|
288 | } | |
|
284 | .submenu { | |
|
285 | display: block; | |
|
286 | } | |
|
289 | 287 | } |
|
290 | 288 | |
|
291 | 289 | .navigation li:last-child .submenu { |
@@ -642,3 +640,45 b' ul#context-pages {' | |||
|
642 | 640 | |
|
643 | 641 | } |
|
644 | 642 | } |
|
643 | ||
|
644 | .main_filter_help_box { | |
|
645 | padding: 7px 7px; | |
|
646 | border-top: 1px solid @grey4; | |
|
647 | border-right: 1px solid @grey4; | |
|
648 | border-bottom: 1px solid @grey4; | |
|
649 | display: inline-block; | |
|
650 | vertical-align: top; | |
|
651 | margin-left: -5px; | |
|
652 | background: @grey3; | |
|
653 | } | |
|
654 | ||
|
655 | .main_filter_input_box { | |
|
656 | display: inline-block; | |
|
657 | } | |
|
658 | ||
|
659 | .main_filter_box { | |
|
660 | margin: 9px 0 0 0; | |
|
661 | } | |
|
662 | ||
|
663 | #main_filter_help { | |
|
664 | background: @grey3; | |
|
665 | border: 1px solid black; | |
|
666 | position: absolute; | |
|
667 | white-space: pre-wrap; | |
|
668 | z-index: 9999; | |
|
669 | color: @nav-grey; | |
|
670 | margin: 1px 7px; | |
|
671 | padding: 0 2px; | |
|
672 | } | |
|
673 | ||
|
674 | .main_filter_input { | |
|
675 | padding: 6px; | |
|
676 | min-width: 220px; | |
|
677 | color: @nav-grey; | |
|
678 | background: @grey3; | |
|
679 | } | |
|
680 | ||
|
681 | .main_filter_input::placeholder { | |
|
682 | color: @nav-grey; | |
|
683 | opacity: 1; | |
|
684 | } |
@@ -228,7 +228,7 b' mark,' | |||
|
228 | 228 | clear: both; |
|
229 | 229 | float: left; |
|
230 | 230 | width: 100%; |
|
231 | margin: @pagepadding 0 @pagepadding; | |
|
231 | margin: @pagepadding/2 0 @pagepadding; | |
|
232 | 232 | |
|
233 | 233 | .breadcrumbs{ |
|
234 | 234 | float: left; |
@@ -20,7 +20,7 b' function setRCMouseBindings(repoName, re' | |||
|
20 | 20 | |
|
21 | 21 | // / open the quick filter |
|
22 | 22 | Mousetrap.bind(['/'], function(e) { |
|
23 | $('#repo_switcher').select2('open'); | |
|
23 | $('#main_filter').get(0).focus(); | |
|
24 | 24 | |
|
25 | 25 | // return false to prevent default browser behavior |
|
26 | 26 | // and stop event from bubbling |
@@ -131,7 +131,7 b' var repoFilter = function(data) {' | |||
|
131 | 131 | |
|
132 | 132 | $.each(data.results[0].children, function() { |
|
133 | 133 | // replace name to ID for submision |
|
134 |
this.id = this. |
|
|
134 | this.id = this.repo_id; | |
|
135 | 135 | results.push(this); |
|
136 | 136 | }); |
|
137 | 137 | |
@@ -154,7 +154,7 b' var selectVcsScope = function() {' | |||
|
154 | 154 | dropdownAutoWidth: true, |
|
155 | 155 | containerCssClass: "drop-menu", |
|
156 | 156 | dropdownCssClass: "drop-menu-dropdown", |
|
157 | formatResult: formatResult, | |
|
157 | formatResult: formatRepoResult, | |
|
158 | 158 | query: $.debounce(250, function(query){ |
|
159 | 159 | self = this; |
|
160 | 160 | var cacheKey = query.term; |
@@ -165,8 +165,8 b' var repoTypeFilter = function(data) {' | |||
|
165 | 165 | |
|
166 | 166 | $.each(data.results[0].children, function() { |
|
167 | 167 | // filter out the SAME repo, it cannot be used as fork of itself |
|
168 |
if (this |
|
|
169 |
this.id = this. |
|
|
168 | if (this.repo_id != currentRepoId) { | |
|
169 | this.id = this.repo_id; | |
|
170 | 170 | results.push(this) |
|
171 | 171 | } |
|
172 | 172 | }); |
@@ -181,7 +181,7 b' var repoTypeFilter = function(data) {' | |||
|
181 | 181 | dropdownAutoWidth: true, |
|
182 | 182 | containerCssClass: "drop-menu", |
|
183 | 183 | dropdownCssClass: "drop-menu-dropdown", |
|
184 | formatResult: formatResult, | |
|
184 | formatResult: formatRepoResult, | |
|
185 | 185 | query: $.debounce(250, function(query){ |
|
186 | 186 | self = this; |
|
187 | 187 | var cacheKey = query.term; |
@@ -129,7 +129,7 b' var repoFilter = function(data) {' | |||
|
129 | 129 | |
|
130 | 130 | $.each(data.results[0].children, function() { |
|
131 | 131 | // replace name to ID for submision |
|
132 |
this.id = this. |
|
|
132 | this.id = this.repo_id; | |
|
133 | 133 | results.push(this); |
|
134 | 134 | }); |
|
135 | 135 | |
@@ -152,7 +152,7 b' var selectVcsScope = function() {' | |||
|
152 | 152 | dropdownAutoWidth: true, |
|
153 | 153 | containerCssClass: "drop-menu", |
|
154 | 154 | dropdownCssClass: "drop-menu-dropdown", |
|
155 | formatResult: formatResult, | |
|
155 | formatResult: formatRepoResult, | |
|
156 | 156 | query: $.debounce(250, function(query){ |
|
157 | 157 | self = this; |
|
158 | 158 | var cacheKey = query.term; |
@@ -226,7 +226,7 b'' | |||
|
226 | 226 | <!--- CONTEXT BAR --> |
|
227 | 227 | <div id="context-bar"> |
|
228 | 228 | <div class="wrapper"> |
|
229 |
<ul id="context-pages" class="horizontal-list |
|
|
229 | <ul id="context-pages" class="navigation horizontal-list"> | |
|
230 | 230 | <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li> |
|
231 | 231 | <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> |
|
232 | 232 | <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> |
@@ -386,10 +386,30 b'' | |||
|
386 | 386 | return "" |
|
387 | 387 | %> |
|
388 | 388 | <ul id="quick" class="main_nav navigation horizontal-list"> |
|
389 | <!-- repo switcher --> | |
|
390 | <li class="${is_active('repositories')} repo_switcher_li has_select2"> | |
|
391 | <input id="repo_switcher" name="repo_switcher" type="hidden"> | |
|
392 | </li> | |
|
389 | ||
|
390 | ## Main filter | |
|
391 | <li> | |
|
392 | <div class="menulabel main_filter_box"> | |
|
393 | <div class="main_filter_input_box"> | |
|
394 | <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/> | |
|
395 | </div> | |
|
396 | <div class="main_filter_help_box"> | |
|
397 | <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a> | |
|
398 | </div> | |
|
399 | </div> | |
|
400 | ||
|
401 | <div id="main_filter_help" style="display: none"> | |
|
402 | Use '/' key to quickly access this field. | |
|
403 | Enter name of repository, or repository group for quick search. | |
|
404 | ||
|
405 | Prefix query to allow special search: | |
|
406 | ||
|
407 | For usernames, e.g user:admin | |
|
408 | ||
|
409 | For commit hash/id, e.g commit:efced4 | |
|
410 | ||
|
411 | </div> | |
|
412 | </li> | |
|
393 | 413 | |
|
394 | 414 | ## ROOT MENU |
|
395 | 415 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
@@ -432,6 +452,9 b'' | |||
|
432 | 452 | c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())} |
|
433 | 453 | </li> |
|
434 | 454 | % endif |
|
455 | ## render extra user menu | |
|
456 | ${usermenu(active=(active=='my_account'))} | |
|
457 | ||
|
435 | 458 |
|
|
436 | 459 | <li class="${is_active('debug_style')}"> |
|
437 | 460 | <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}"> |
@@ -439,102 +462,127 b'' | |||
|
439 | 462 | </a> |
|
440 | 463 | </li> |
|
441 | 464 | % endif |
|
442 | ## render extra user menu | |
|
443 | ${usermenu(active=(active=='my_account'))} | |
|
444 | 465 | </ul> |
|
445 | 466 | |
|
446 | 467 | <script type="text/javascript"> |
|
447 |
var visual |
|
|
448 | ||
|
449 | /*format the look of items in the list*/ | |
|
450 | var format = function(state, escapeMarkup){ | |
|
451 | if (!state.id){ | |
|
452 | return state.text; // optgroup | |
|
453 | } | |
|
454 | var obj_dict = state.obj; | |
|
455 | var tmpl = ''; | |
|
468 | var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True"; | |
|
456 | 469 | |
|
457 | if(obj_dict && state.type == 'repo'){ | |
|
458 | if(obj_dict['repo_type'] === 'hg'){ | |
|
459 | tmpl += '<i class="icon-hg"></i> '; | |
|
460 | } | |
|
461 | else if(obj_dict['repo_type'] === 'git'){ | |
|
462 | tmpl += '<i class="icon-git"></i> '; | |
|
463 | } | |
|
464 | else if(obj_dict['repo_type'] === 'svn'){ | |
|
465 | tmpl += '<i class="icon-svn"></i> '; | |
|
470 | var formatRepoResult = function(result, container, query, escapeMarkup) { | |
|
471 | return function(data, escapeMarkup) { | |
|
472 | if (!data.repo_id){ | |
|
473 | return data.text; // optgroup text Repositories | |
|
466 | 474 | } |
|
467 | if(obj_dict['private']){ | |
|
468 |
|
|
|
469 | } | |
|
470 | else if(visual_show_public_icon){ | |
|
471 | tmpl += '<i class="icon-unlock-alt"></i> '; | |
|
475 | ||
|
476 | var tmpl = ''; | |
|
477 | var repoType = data['repo_type']; | |
|
478 | var repoName = data['text']; | |
|
479 | ||
|
480 | if(data && data.type == 'repo'){ | |
|
481 | if(repoType === 'hg'){ | |
|
482 | tmpl += '<i class="icon-hg"></i> '; | |
|
483 | } | |
|
484 | else if(repoType === 'git'){ | |
|
485 | tmpl += '<i class="icon-git"></i> '; | |
|
486 | } | |
|
487 | else if(repoType === 'svn'){ | |
|
488 | tmpl += '<i class="icon-svn"></i> '; | |
|
489 | } | |
|
490 | if(data['private']){ | |
|
491 | tmpl += '<i class="icon-lock" ></i> '; | |
|
492 | } | |
|
493 | else if(visualShowPublicIcon){ | |
|
494 | tmpl += '<i class="icon-unlock-alt"></i> '; | |
|
495 | } | |
|
472 | 496 | } |
|
473 | } | |
|
474 | if(obj_dict && state.type == 'commit') { | |
|
475 | tmpl += '<i class="icon-tag"></i>'; | |
|
476 | } | |
|
477 | if(obj_dict && state.type == 'group'){ | |
|
478 | tmpl += '<i class="icon-folder-close"></i> '; | |
|
479 | } | |
|
480 | tmpl += escapeMarkup(state.text); | |
|
481 | return tmpl; | |
|
482 | }; | |
|
497 | tmpl += escapeMarkup(repoName); | |
|
498 | return tmpl; | |
|
483 | 499 | |
|
484 | var formatResult = function(result, container, query, escapeMarkup) { | |
|
485 | return format(result, escapeMarkup); | |
|
486 | }; | |
|
487 | ||
|
488 | var formatSelection = function(data, container, escapeMarkup) { | |
|
489 | return format(data, escapeMarkup); | |
|
500 | }(result, escapeMarkup); | |
|
490 | 501 | }; |
|
491 | 502 | |
|
492 | $("#repo_switcher").select2({ | |
|
493 | cachedDataSource: {}, | |
|
494 | minimumInputLength: 2, | |
|
495 | placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>', | |
|
496 | dropdownAutoWidth: true, | |
|
497 | formatResult: formatResult, | |
|
498 | formatSelection: formatSelection, | |
|
499 | containerCssClass: "repo-switcher", | |
|
500 | dropdownCssClass: "repo-switcher-dropdown", | |
|
501 | escapeMarkup: function(m){ | |
|
502 | // don't escape our custom placeholder | |
|
503 | if(m.substr(0,23) == '<div class="menulabel">'){ | |
|
504 |
|
|
|
505 | } | |
|
503 | ||
|
504 | var autocompleteMainFilterFormatResult = function (data, value, org_formatter) { | |
|
505 | ||
|
506 | if (value.split(':').length === 2) { | |
|
507 | value = value.split(':')[1] | |
|
508 | } | |
|
509 | ||
|
510 | var searchType = data['type']; | |
|
511 | var valueDisplay = data['value_display']; | |
|
512 | ||
|
513 | var escapeRegExChars = function (value) { | |
|
514 | return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); | |
|
515 | }; | |
|
516 | var pattern = '(' + escapeRegExChars(value) + ')'; | |
|
517 | ||
|
518 | // highlight match | |
|
519 | valueDisplay = Select2.util.escapeMarkup(valueDisplay); | |
|
520 | valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); | |
|
521 | ||
|
522 | var icon = ''; | |
|
506 | 523 | |
|
507 | return Select2.util.escapeMarkup(m); | |
|
508 | }, | |
|
509 | query: $.debounce(250, function(query){ | |
|
510 | self = this; | |
|
511 | var cacheKey = query.term; | |
|
512 | var cachedData = self.cachedDataSource[cacheKey]; | |
|
524 | if (searchType === 'search') { | |
|
525 | icon += '<i class="icon-more"></i> '; | |
|
526 | } | |
|
527 | else if (searchType === 'repo') { | |
|
528 | if (data['repo_type'] === 'hg') { | |
|
529 | icon += '<i class="icon-hg"></i> '; | |
|
530 | } | |
|
531 | else if (data['repo_type'] === 'git') { | |
|
532 | icon += '<i class="icon-git"></i> '; | |
|
533 | } | |
|
534 | else if (data['repo_type'] === 'svn') { | |
|
535 | icon += '<i class="icon-svn"></i> '; | |
|
536 | } | |
|
537 | if (data['private']) { | |
|
538 | icon += '<i class="icon-lock" ></i> '; | |
|
539 | } | |
|
540 | else if (visualShowPublicIcon) { | |
|
541 | icon += '<i class="icon-unlock-alt"></i> '; | |
|
542 | } | |
|
543 | } | |
|
544 | else if (searchType === 'repo_group') { | |
|
545 | icon += '<i class="icon-folder-close"></i> '; | |
|
546 | } | |
|
547 | else if (searchType === 'user') { | |
|
548 | icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']); | |
|
549 | } | |
|
550 | else if (searchType === 'commit') { | |
|
551 | icon += '<i class="icon-tag"></i>'; | |
|
552 | } | |
|
513 | 553 | |
|
514 | if (cachedData) { | |
|
515 | query.callback({results: cachedData.results}); | |
|
516 | } else { | |
|
517 | $.ajax({ | |
|
518 | url: pyroutes.url('goto_switcher_data'), | |
|
519 | data: {'query': query.term}, | |
|
520 | dataType: 'json', | |
|
521 | type: 'GET', | |
|
522 | success: function(data) { | |
|
523 | self.cachedDataSource[cacheKey] = data; | |
|
524 | query.callback({results: data.results}); | |
|
525 | }, | |
|
526 | error: function(data, textStatus, errorThrown) { | |
|
527 | alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText)); | |
|
528 | } | |
|
529 | }) | |
|
530 |
|
|
|
531 |
|
|
|
554 | var tmpl = '<div class="ac-container-wrap">{0}{1}</div>'; | |
|
555 | return tmpl.format(icon, valueDisplay); | |
|
556 | }; | |
|
557 | ||
|
558 | var handleSelect = function(element, suggestion) { | |
|
559 | window.location = suggestion['url']; | |
|
560 | }; | |
|
561 | var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) { | |
|
562 | if (queryLowerCase.split(':').length === 2) { | |
|
563 | queryLowerCase = queryLowerCase.split(':')[1] | |
|
564 | } | |
|
565 | return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1; | |
|
566 | }; | |
|
567 | ||
|
568 | $('#main_filter').autocomplete({ | |
|
569 | serviceUrl: pyroutes.url('goto_switcher_data'), | |
|
570 | minChars:2, | |
|
571 | maxHeight:400, | |
|
572 | deferRequestBy: 300, //miliseconds | |
|
573 | tabDisabled: true, | |
|
574 | autoSelectFirst: true, | |
|
575 | formatResult: autocompleteMainFilterFormatResult, | |
|
576 | lookupFilter: autocompleteMainFilterResult, | |
|
577 | onSelect: function(element, suggestion){ | |
|
578 | handleSelect(element, suggestion); | |
|
579 | return false; | |
|
580 | } | |
|
532 | 581 | }); |
|
533 | 582 | |
|
534 | $("#repo_switcher").on('select2-selecting', function(e){ | |
|
535 | e.preventDefault(); | |
|
536 | window.location = e.choice.url; | |
|
537 | }); | |
|
583 | showMainFilterBox = function () { | |
|
584 | $('#main_filter_help').toggle(); | |
|
585 | } | |
|
538 | 586 | |
|
539 | 587 | </script> |
|
540 | 588 | <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script> |
@@ -557,7 +605,7 b'' | |||
|
557 | 605 | </tr> |
|
558 | 606 | <% |
|
559 | 607 | elems = [ |
|
560 |
('/', ' |
|
|
608 | ('/', 'Use quick search box'), | |
|
561 | 609 | ('g h', 'Goto home page'), |
|
562 | 610 | ('g g', 'Goto my private gists page'), |
|
563 | 611 | ('g G', 'Goto my public gists page'), |
@@ -611,3 +659,4 b'' | |||
|
611 | 659 | </div><!-- /.modal-content --> |
|
612 | 660 | </div><!-- /.modal-dialog --> |
|
613 | 661 | </div><!-- /.modal --> |
|
662 |
@@ -5,9 +5,8 b'' | |||
|
5 | 5 | <!-- box / title --> |
|
6 | 6 | <div class="title"> |
|
7 | 7 | <div class="block-left breadcrumbs"> |
|
8 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/> | |
|
9 | 8 | ${self.breadcrumbs()} |
|
10 |
<span id="match_container" style="display:none"> |
|
|
9 | <span id="match_container" style="display:none"><span id="match_count">0</span> ${_('matches')}</span> | |
|
11 | 10 | </div> |
|
12 | 11 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
|
13 | 12 | <div class="block-right"> |
@@ -137,65 +136,6 b'' | |||
|
137 | 136 | }); |
|
138 | 137 | % endif |
|
139 | 138 | |
|
140 | var getDatatableCount = function() { | |
|
141 | var reposCount = 0; | |
|
142 | var reposCountTotal = 0; | |
|
143 | ||
|
144 | % if c.repos_data != '[]': | |
|
145 | var pageInfo = $('#repo_list_table').dataTable().api().page.info(); | |
|
146 | var reposCount = pageInfo.recordsDisplay; | |
|
147 | var reposCountTotal = pageInfo.recordsTotal; | |
|
148 | % endif | |
|
149 | ||
|
150 | var repoGroupsCount = 0; | |
|
151 | var repoGroupsCountTotal = 0; | |
|
152 | ||
|
153 | % if c.repo_groups_data != '[]': | |
|
154 | var pageInfo = $('#group_list_table').dataTable().api().page.info(); | |
|
155 | var repoGroupsCount = pageInfo.recordsDisplay; | |
|
156 | var repoGroupsCountTotal = pageInfo.recordsTotal; | |
|
157 | % endif | |
|
158 | ||
|
159 | if (repoGroupsCount !== repoGroupsCountTotal) { | |
|
160 | $('#match_count').text(reposCount + repoGroupsCount); | |
|
161 | } | |
|
162 | if (reposCount !== reposCountTotal) { | |
|
163 | $('#match_container').show(); | |
|
164 | } | |
|
165 | if ($('#q_filter').val() === '') { | |
|
166 | $('#match_container').hide(); | |
|
167 | } | |
|
168 | }; | |
|
169 | ||
|
170 | // update the counter when doing search | |
|
171 | $('#repo_list_table, #group_list_table').on( 'search.dt', function (e,settings) { | |
|
172 | getDatatableCount(); | |
|
173 | }); | |
|
174 | ||
|
175 | // filter, filter both grids | |
|
176 | $('#q_filter').on( 'keyup', function () { | |
|
177 | ||
|
178 | % if c.repo_groups_data != '[]': | |
|
179 | var repo_group_api = $('#group_list_table').dataTable().api(); | |
|
180 | repo_group_api | |
|
181 | .columns( 0 ) | |
|
182 | .search( this.value ) | |
|
183 | .draw(); | |
|
184 | % endif | |
|
185 | ||
|
186 | % if c.repos_data != '[]': | |
|
187 | var repo_api = $('#repo_list_table').dataTable().api(); | |
|
188 | repo_api | |
|
189 | .columns( 0 ) | |
|
190 | .search( this.value ) | |
|
191 | .draw(); | |
|
192 | % endif | |
|
193 | ||
|
194 | }); | |
|
195 | ||
|
196 | // refilter table if page load via back button | |
|
197 | $("#q_filter").trigger('keyup'); | |
|
198 | ||
|
199 | 139 | }); |
|
200 | 140 | </script> |
|
201 | 141 | </%def> |
General Comments 0
You need to be logged in to leave comments.
Login now