##// END OF EJS Templates
ui: fixed branding look&feel as per discussions.
dan -
r3543:692134f0 default
parent child Browse files
Show More
@@ -1,744 +1,743 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23
23
24 import rhodecode
24 import rhodecode
25 from rhodecode.apps._base import ADMIN_PREFIX
25 from rhodecode.apps._base import ADMIN_PREFIX
26 from rhodecode.lib.utils2 import md5
26 from rhodecode.lib.utils2 import md5
27 from rhodecode.model.db import RhodeCodeUi
27 from rhodecode.model.db import RhodeCodeUi
28 from rhodecode.model.meta import Session
28 from rhodecode.model.meta import Session
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
30 from rhodecode.tests import assert_session_flash
30 from rhodecode.tests import assert_session_flash
31 from rhodecode.tests.utils import AssertResponse
31 from rhodecode.tests.utils import AssertResponse
32
32
33
33
34 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
34 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
35
35
36
36
37 def route_path(name, params=None, **kwargs):
37 def route_path(name, params=None, **kwargs):
38 import urllib
38 import urllib
39 from rhodecode.apps._base import ADMIN_PREFIX
39 from rhodecode.apps._base import ADMIN_PREFIX
40
40
41 base_url = {
41 base_url = {
42
42
43 'admin_settings':
43 'admin_settings':
44 ADMIN_PREFIX +'/settings',
44 ADMIN_PREFIX +'/settings',
45 'admin_settings_update':
45 'admin_settings_update':
46 ADMIN_PREFIX + '/settings/update',
46 ADMIN_PREFIX + '/settings/update',
47 'admin_settings_global':
47 'admin_settings_global':
48 ADMIN_PREFIX + '/settings/global',
48 ADMIN_PREFIX + '/settings/global',
49 'admin_settings_global_update':
49 'admin_settings_global_update':
50 ADMIN_PREFIX + '/settings/global/update',
50 ADMIN_PREFIX + '/settings/global/update',
51 'admin_settings_vcs':
51 'admin_settings_vcs':
52 ADMIN_PREFIX + '/settings/vcs',
52 ADMIN_PREFIX + '/settings/vcs',
53 'admin_settings_vcs_update':
53 'admin_settings_vcs_update':
54 ADMIN_PREFIX + '/settings/vcs/update',
54 ADMIN_PREFIX + '/settings/vcs/update',
55 'admin_settings_vcs_svn_pattern_delete':
55 'admin_settings_vcs_svn_pattern_delete':
56 ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete',
56 ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete',
57 'admin_settings_mapping':
57 'admin_settings_mapping':
58 ADMIN_PREFIX + '/settings/mapping',
58 ADMIN_PREFIX + '/settings/mapping',
59 'admin_settings_mapping_update':
59 'admin_settings_mapping_update':
60 ADMIN_PREFIX + '/settings/mapping/update',
60 ADMIN_PREFIX + '/settings/mapping/update',
61 'admin_settings_visual':
61 'admin_settings_visual':
62 ADMIN_PREFIX + '/settings/visual',
62 ADMIN_PREFIX + '/settings/visual',
63 'admin_settings_visual_update':
63 'admin_settings_visual_update':
64 ADMIN_PREFIX + '/settings/visual/update',
64 ADMIN_PREFIX + '/settings/visual/update',
65 'admin_settings_issuetracker':
65 'admin_settings_issuetracker':
66 ADMIN_PREFIX + '/settings/issue-tracker',
66 ADMIN_PREFIX + '/settings/issue-tracker',
67 'admin_settings_issuetracker_update':
67 'admin_settings_issuetracker_update':
68 ADMIN_PREFIX + '/settings/issue-tracker/update',
68 ADMIN_PREFIX + '/settings/issue-tracker/update',
69 'admin_settings_issuetracker_test':
69 'admin_settings_issuetracker_test':
70 ADMIN_PREFIX + '/settings/issue-tracker/test',
70 ADMIN_PREFIX + '/settings/issue-tracker/test',
71 'admin_settings_issuetracker_delete':
71 'admin_settings_issuetracker_delete':
72 ADMIN_PREFIX + '/settings/issue-tracker/delete',
72 ADMIN_PREFIX + '/settings/issue-tracker/delete',
73 'admin_settings_email':
73 'admin_settings_email':
74 ADMIN_PREFIX + '/settings/email',
74 ADMIN_PREFIX + '/settings/email',
75 'admin_settings_email_update':
75 'admin_settings_email_update':
76 ADMIN_PREFIX + '/settings/email/update',
76 ADMIN_PREFIX + '/settings/email/update',
77 'admin_settings_hooks':
77 'admin_settings_hooks':
78 ADMIN_PREFIX + '/settings/hooks',
78 ADMIN_PREFIX + '/settings/hooks',
79 'admin_settings_hooks_update':
79 'admin_settings_hooks_update':
80 ADMIN_PREFIX + '/settings/hooks/update',
80 ADMIN_PREFIX + '/settings/hooks/update',
81 'admin_settings_hooks_delete':
81 'admin_settings_hooks_delete':
82 ADMIN_PREFIX + '/settings/hooks/delete',
82 ADMIN_PREFIX + '/settings/hooks/delete',
83 'admin_settings_search':
83 'admin_settings_search':
84 ADMIN_PREFIX + '/settings/search',
84 ADMIN_PREFIX + '/settings/search',
85 'admin_settings_labs':
85 'admin_settings_labs':
86 ADMIN_PREFIX + '/settings/labs',
86 ADMIN_PREFIX + '/settings/labs',
87 'admin_settings_labs_update':
87 'admin_settings_labs_update':
88 ADMIN_PREFIX + '/settings/labs/update',
88 ADMIN_PREFIX + '/settings/labs/update',
89
89
90 'admin_settings_sessions':
90 'admin_settings_sessions':
91 ADMIN_PREFIX + '/settings/sessions',
91 ADMIN_PREFIX + '/settings/sessions',
92 'admin_settings_sessions_cleanup':
92 'admin_settings_sessions_cleanup':
93 ADMIN_PREFIX + '/settings/sessions/cleanup',
93 ADMIN_PREFIX + '/settings/sessions/cleanup',
94 'admin_settings_system':
94 'admin_settings_system':
95 ADMIN_PREFIX + '/settings/system',
95 ADMIN_PREFIX + '/settings/system',
96 'admin_settings_system_update':
96 'admin_settings_system_update':
97 ADMIN_PREFIX + '/settings/system/updates',
97 ADMIN_PREFIX + '/settings/system/updates',
98 'admin_settings_open_source':
98 'admin_settings_open_source':
99 ADMIN_PREFIX + '/settings/open_source',
99 ADMIN_PREFIX + '/settings/open_source',
100
100
101
101
102 }[name].format(**kwargs)
102 }[name].format(**kwargs)
103
103
104 if params:
104 if params:
105 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
105 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
106 return base_url
106 return base_url
107
107
108
108
109 @pytest.mark.usefixtures('autologin_user', 'app')
109 @pytest.mark.usefixtures('autologin_user', 'app')
110 class TestAdminSettingsController(object):
110 class TestAdminSettingsController(object):
111
111
112 @pytest.mark.parametrize('urlname', [
112 @pytest.mark.parametrize('urlname', [
113 'admin_settings_vcs',
113 'admin_settings_vcs',
114 'admin_settings_mapping',
114 'admin_settings_mapping',
115 'admin_settings_global',
115 'admin_settings_global',
116 'admin_settings_visual',
116 'admin_settings_visual',
117 'admin_settings_email',
117 'admin_settings_email',
118 'admin_settings_hooks',
118 'admin_settings_hooks',
119 'admin_settings_search',
119 'admin_settings_search',
120 ])
120 ])
121 def test_simple_get(self, urlname):
121 def test_simple_get(self, urlname):
122 self.app.get(route_path(urlname))
122 self.app.get(route_path(urlname))
123
123
124 def test_create_custom_hook(self, csrf_token):
124 def test_create_custom_hook(self, csrf_token):
125 response = self.app.post(
125 response = self.app.post(
126 route_path('admin_settings_hooks_update'),
126 route_path('admin_settings_hooks_update'),
127 params={
127 params={
128 'new_hook_ui_key': 'test_hooks_1',
128 'new_hook_ui_key': 'test_hooks_1',
129 'new_hook_ui_value': 'cd /tmp',
129 'new_hook_ui_value': 'cd /tmp',
130 'csrf_token': csrf_token})
130 'csrf_token': csrf_token})
131
131
132 response = response.follow()
132 response = response.follow()
133 response.mustcontain('test_hooks_1')
133 response.mustcontain('test_hooks_1')
134 response.mustcontain('cd /tmp')
134 response.mustcontain('cd /tmp')
135
135
136 def test_create_custom_hook_delete(self, csrf_token):
136 def test_create_custom_hook_delete(self, csrf_token):
137 response = self.app.post(
137 response = self.app.post(
138 route_path('admin_settings_hooks_update'),
138 route_path('admin_settings_hooks_update'),
139 params={
139 params={
140 'new_hook_ui_key': 'test_hooks_2',
140 'new_hook_ui_key': 'test_hooks_2',
141 'new_hook_ui_value': 'cd /tmp2',
141 'new_hook_ui_value': 'cd /tmp2',
142 'csrf_token': csrf_token})
142 'csrf_token': csrf_token})
143
143
144 response = response.follow()
144 response = response.follow()
145 response.mustcontain('test_hooks_2')
145 response.mustcontain('test_hooks_2')
146 response.mustcontain('cd /tmp2')
146 response.mustcontain('cd /tmp2')
147
147
148 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
148 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
149
149
150 # delete
150 # delete
151 self.app.post(
151 self.app.post(
152 route_path('admin_settings_hooks_delete'),
152 route_path('admin_settings_hooks_delete'),
153 params={'hook_id': hook_id, 'csrf_token': csrf_token})
153 params={'hook_id': hook_id, 'csrf_token': csrf_token})
154 response = self.app.get(route_path('admin_settings_hooks'))
154 response = self.app.get(route_path('admin_settings_hooks'))
155 response.mustcontain(no=['test_hooks_2'])
155 response.mustcontain(no=['test_hooks_2'])
156 response.mustcontain(no=['cd /tmp2'])
156 response.mustcontain(no=['cd /tmp2'])
157
157
158
158
159 @pytest.mark.usefixtures('autologin_user', 'app')
159 @pytest.mark.usefixtures('autologin_user', 'app')
160 class TestAdminSettingsGlobal(object):
160 class TestAdminSettingsGlobal(object):
161
161
162 def test_pre_post_code_code_active(self, csrf_token):
162 def test_pre_post_code_code_active(self, csrf_token):
163 pre_code = 'rc-pre-code-187652122'
163 pre_code = 'rc-pre-code-187652122'
164 post_code = 'rc-postcode-98165231'
164 post_code = 'rc-postcode-98165231'
165
165
166 response = self.post_and_verify_settings({
166 response = self.post_and_verify_settings({
167 'rhodecode_pre_code': pre_code,
167 'rhodecode_pre_code': pre_code,
168 'rhodecode_post_code': post_code,
168 'rhodecode_post_code': post_code,
169 'csrf_token': csrf_token,
169 'csrf_token': csrf_token,
170 })
170 })
171
171
172 response = response.follow()
172 response = response.follow()
173 response.mustcontain(pre_code, post_code)
173 response.mustcontain(pre_code, post_code)
174
174
175 def test_pre_post_code_code_inactive(self, csrf_token):
175 def test_pre_post_code_code_inactive(self, csrf_token):
176 pre_code = 'rc-pre-code-187652122'
176 pre_code = 'rc-pre-code-187652122'
177 post_code = 'rc-postcode-98165231'
177 post_code = 'rc-postcode-98165231'
178 response = self.post_and_verify_settings({
178 response = self.post_and_verify_settings({
179 'rhodecode_pre_code': '',
179 'rhodecode_pre_code': '',
180 'rhodecode_post_code': '',
180 'rhodecode_post_code': '',
181 'csrf_token': csrf_token,
181 'csrf_token': csrf_token,
182 })
182 })
183
183
184 response = response.follow()
184 response = response.follow()
185 response.mustcontain(no=[pre_code, post_code])
185 response.mustcontain(no=[pre_code, post_code])
186
186
187 def test_captcha_activate(self, csrf_token):
187 def test_captcha_activate(self, csrf_token):
188 self.post_and_verify_settings({
188 self.post_and_verify_settings({
189 'rhodecode_captcha_private_key': '1234567890',
189 'rhodecode_captcha_private_key': '1234567890',
190 'rhodecode_captcha_public_key': '1234567890',
190 'rhodecode_captcha_public_key': '1234567890',
191 'csrf_token': csrf_token,
191 'csrf_token': csrf_token,
192 })
192 })
193
193
194 response = self.app.get(ADMIN_PREFIX + '/register')
194 response = self.app.get(ADMIN_PREFIX + '/register')
195 response.mustcontain('captcha')
195 response.mustcontain('captcha')
196
196
197 def test_captcha_deactivate(self, csrf_token):
197 def test_captcha_deactivate(self, csrf_token):
198 self.post_and_verify_settings({
198 self.post_and_verify_settings({
199 'rhodecode_captcha_private_key': '',
199 'rhodecode_captcha_private_key': '',
200 'rhodecode_captcha_public_key': '1234567890',
200 'rhodecode_captcha_public_key': '1234567890',
201 'csrf_token': csrf_token,
201 'csrf_token': csrf_token,
202 })
202 })
203
203
204 response = self.app.get(ADMIN_PREFIX + '/register')
204 response = self.app.get(ADMIN_PREFIX + '/register')
205 response.mustcontain(no=['captcha'])
205 response.mustcontain(no=['captcha'])
206
206
207 def test_title_change(self, csrf_token):
207 def test_title_change(self, csrf_token):
208 old_title = 'RhodeCode'
208 old_title = 'RhodeCode'
209
209
210 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
210 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
211 response = self.post_and_verify_settings({
211 response = self.post_and_verify_settings({
212 'rhodecode_title': new_title,
212 'rhodecode_title': new_title,
213 'csrf_token': csrf_token,
213 'csrf_token': csrf_token,
214 })
214 })
215
215
216 response = response.follow()
216 response = response.follow()
217 response.mustcontain(
217 response.mustcontain(new_title)
218 """<div class="branding">- %s</div>""" % new_title)
219
218
220 def post_and_verify_settings(self, settings):
219 def post_and_verify_settings(self, settings):
221 old_title = 'RhodeCode'
220 old_title = 'RhodeCode'
222 old_realm = 'RhodeCode authentication'
221 old_realm = 'RhodeCode authentication'
223 params = {
222 params = {
224 'rhodecode_title': old_title,
223 'rhodecode_title': old_title,
225 'rhodecode_realm': old_realm,
224 'rhodecode_realm': old_realm,
226 'rhodecode_pre_code': '',
225 'rhodecode_pre_code': '',
227 'rhodecode_post_code': '',
226 'rhodecode_post_code': '',
228 'rhodecode_captcha_private_key': '',
227 'rhodecode_captcha_private_key': '',
229 'rhodecode_captcha_public_key': '',
228 'rhodecode_captcha_public_key': '',
230 'rhodecode_create_personal_repo_group': False,
229 'rhodecode_create_personal_repo_group': False,
231 'rhodecode_personal_repo_group_pattern': '${username}',
230 'rhodecode_personal_repo_group_pattern': '${username}',
232 }
231 }
233 params.update(settings)
232 params.update(settings)
234 response = self.app.post(
233 response = self.app.post(
235 route_path('admin_settings_global_update'), params=params)
234 route_path('admin_settings_global_update'), params=params)
236
235
237 assert_session_flash(response, 'Updated application settings')
236 assert_session_flash(response, 'Updated application settings')
238 app_settings = SettingsModel().get_all_settings()
237 app_settings = SettingsModel().get_all_settings()
239 del settings['csrf_token']
238 del settings['csrf_token']
240 for key, value in settings.iteritems():
239 for key, value in settings.iteritems():
241 assert app_settings[key] == value.decode('utf-8')
240 assert app_settings[key] == value.decode('utf-8')
242
241
243 return response
242 return response
244
243
245
244
246 @pytest.mark.usefixtures('autologin_user', 'app')
245 @pytest.mark.usefixtures('autologin_user', 'app')
247 class TestAdminSettingsVcs(object):
246 class TestAdminSettingsVcs(object):
248
247
249 def test_contains_svn_default_patterns(self):
248 def test_contains_svn_default_patterns(self):
250 response = self.app.get(route_path('admin_settings_vcs'))
249 response = self.app.get(route_path('admin_settings_vcs'))
251 expected_patterns = [
250 expected_patterns = [
252 '/trunk',
251 '/trunk',
253 '/branches/*',
252 '/branches/*',
254 '/tags/*',
253 '/tags/*',
255 ]
254 ]
256 for pattern in expected_patterns:
255 for pattern in expected_patterns:
257 response.mustcontain(pattern)
256 response.mustcontain(pattern)
258
257
259 def test_add_new_svn_branch_and_tag_pattern(
258 def test_add_new_svn_branch_and_tag_pattern(
260 self, backend_svn, form_defaults, disable_sql_cache,
259 self, backend_svn, form_defaults, disable_sql_cache,
261 csrf_token):
260 csrf_token):
262 form_defaults.update({
261 form_defaults.update({
263 'new_svn_branch': '/exp/branches/*',
262 'new_svn_branch': '/exp/branches/*',
264 'new_svn_tag': '/important_tags/*',
263 'new_svn_tag': '/important_tags/*',
265 'csrf_token': csrf_token,
264 'csrf_token': csrf_token,
266 })
265 })
267
266
268 response = self.app.post(
267 response = self.app.post(
269 route_path('admin_settings_vcs_update'),
268 route_path('admin_settings_vcs_update'),
270 params=form_defaults, status=302)
269 params=form_defaults, status=302)
271 response = response.follow()
270 response = response.follow()
272
271
273 # Expect to find the new values on the page
272 # Expect to find the new values on the page
274 response.mustcontain('/exp/branches/*')
273 response.mustcontain('/exp/branches/*')
275 response.mustcontain('/important_tags/*')
274 response.mustcontain('/important_tags/*')
276
275
277 # Expect that those patterns are used to match branches and tags now
276 # Expect that those patterns are used to match branches and tags now
278 repo = backend_svn['svn-simple-layout'].scm_instance()
277 repo = backend_svn['svn-simple-layout'].scm_instance()
279 assert 'exp/branches/exp-sphinx-docs' in repo.branches
278 assert 'exp/branches/exp-sphinx-docs' in repo.branches
280 assert 'important_tags/v0.5' in repo.tags
279 assert 'important_tags/v0.5' in repo.tags
281
280
282 def test_add_same_svn_value_twice_shows_an_error_message(
281 def test_add_same_svn_value_twice_shows_an_error_message(
283 self, form_defaults, csrf_token, settings_util):
282 self, form_defaults, csrf_token, settings_util):
284 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
283 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
285 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
284 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
286
285
287 response = self.app.post(
286 response = self.app.post(
288 route_path('admin_settings_vcs_update'),
287 route_path('admin_settings_vcs_update'),
289 params={
288 params={
290 'paths_root_path': form_defaults['paths_root_path'],
289 'paths_root_path': form_defaults['paths_root_path'],
291 'new_svn_branch': '/test',
290 'new_svn_branch': '/test',
292 'new_svn_tag': '/test',
291 'new_svn_tag': '/test',
293 'csrf_token': csrf_token,
292 'csrf_token': csrf_token,
294 },
293 },
295 status=200)
294 status=200)
296
295
297 response.mustcontain("Pattern already exists")
296 response.mustcontain("Pattern already exists")
298 response.mustcontain("Some form inputs contain invalid data.")
297 response.mustcontain("Some form inputs contain invalid data.")
299
298
300 @pytest.mark.parametrize('section', [
299 @pytest.mark.parametrize('section', [
301 'vcs_svn_branch',
300 'vcs_svn_branch',
302 'vcs_svn_tag',
301 'vcs_svn_tag',
303 ])
302 ])
304 def test_delete_svn_patterns(
303 def test_delete_svn_patterns(
305 self, section, csrf_token, settings_util):
304 self, section, csrf_token, settings_util):
306 setting = settings_util.create_rhodecode_ui(
305 setting = settings_util.create_rhodecode_ui(
307 section, '/test_delete', cleanup=False)
306 section, '/test_delete', cleanup=False)
308
307
309 self.app.post(
308 self.app.post(
310 route_path('admin_settings_vcs_svn_pattern_delete'),
309 route_path('admin_settings_vcs_svn_pattern_delete'),
311 params={
310 params={
312 'delete_svn_pattern': setting.ui_id,
311 'delete_svn_pattern': setting.ui_id,
313 'csrf_token': csrf_token},
312 'csrf_token': csrf_token},
314 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
313 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
315
314
316 @pytest.mark.parametrize('section', [
315 @pytest.mark.parametrize('section', [
317 'vcs_svn_branch',
316 'vcs_svn_branch',
318 'vcs_svn_tag',
317 'vcs_svn_tag',
319 ])
318 ])
320 def test_delete_svn_patterns_raises_404_when_no_xhr(
319 def test_delete_svn_patterns_raises_404_when_no_xhr(
321 self, section, csrf_token, settings_util):
320 self, section, csrf_token, settings_util):
322 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
321 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
323
322
324 self.app.post(
323 self.app.post(
325 route_path('admin_settings_vcs_svn_pattern_delete'),
324 route_path('admin_settings_vcs_svn_pattern_delete'),
326 params={
325 params={
327 'delete_svn_pattern': setting.ui_id,
326 'delete_svn_pattern': setting.ui_id,
328 'csrf_token': csrf_token},
327 'csrf_token': csrf_token},
329 status=404)
328 status=404)
330
329
331 def test_extensions_hgsubversion(self, form_defaults, csrf_token):
330 def test_extensions_hgsubversion(self, form_defaults, csrf_token):
332 form_defaults.update({
331 form_defaults.update({
333 'csrf_token': csrf_token,
332 'csrf_token': csrf_token,
334 'extensions_hgsubversion': 'True',
333 'extensions_hgsubversion': 'True',
335 })
334 })
336 response = self.app.post(
335 response = self.app.post(
337 route_path('admin_settings_vcs_update'),
336 route_path('admin_settings_vcs_update'),
338 params=form_defaults,
337 params=form_defaults,
339 status=302)
338 status=302)
340
339
341 response = response.follow()
340 response = response.follow()
342 extensions_input = (
341 extensions_input = (
343 '<input id="extensions_hgsubversion" '
342 '<input id="extensions_hgsubversion" '
344 'name="extensions_hgsubversion" type="checkbox" '
343 'name="extensions_hgsubversion" type="checkbox" '
345 'value="True" checked="checked" />')
344 'value="True" checked="checked" />')
346 response.mustcontain(extensions_input)
345 response.mustcontain(extensions_input)
347
346
348 def test_extensions_hgevolve(self, form_defaults, csrf_token):
347 def test_extensions_hgevolve(self, form_defaults, csrf_token):
349 form_defaults.update({
348 form_defaults.update({
350 'csrf_token': csrf_token,
349 'csrf_token': csrf_token,
351 'extensions_evolve': 'True',
350 'extensions_evolve': 'True',
352 })
351 })
353 response = self.app.post(
352 response = self.app.post(
354 route_path('admin_settings_vcs_update'),
353 route_path('admin_settings_vcs_update'),
355 params=form_defaults,
354 params=form_defaults,
356 status=302)
355 status=302)
357
356
358 response = response.follow()
357 response = response.follow()
359 extensions_input = (
358 extensions_input = (
360 '<input id="extensions_evolve" '
359 '<input id="extensions_evolve" '
361 'name="extensions_evolve" type="checkbox" '
360 'name="extensions_evolve" type="checkbox" '
362 'value="True" checked="checked" />')
361 'value="True" checked="checked" />')
363 response.mustcontain(extensions_input)
362 response.mustcontain(extensions_input)
364
363
365 def test_has_a_section_for_pull_request_settings(self):
364 def test_has_a_section_for_pull_request_settings(self):
366 response = self.app.get(route_path('admin_settings_vcs'))
365 response = self.app.get(route_path('admin_settings_vcs'))
367 response.mustcontain('Pull Request Settings')
366 response.mustcontain('Pull Request Settings')
368
367
369 def test_has_an_input_for_invalidation_of_inline_comments(self):
368 def test_has_an_input_for_invalidation_of_inline_comments(self):
370 response = self.app.get(route_path('admin_settings_vcs'))
369 response = self.app.get(route_path('admin_settings_vcs'))
371 assert_response = AssertResponse(response)
370 assert_response = AssertResponse(response)
372 assert_response.one_element_exists(
371 assert_response.one_element_exists(
373 '[name=rhodecode_use_outdated_comments]')
372 '[name=rhodecode_use_outdated_comments]')
374
373
375 @pytest.mark.parametrize('new_value', [True, False])
374 @pytest.mark.parametrize('new_value', [True, False])
376 def test_allows_to_change_invalidation_of_inline_comments(
375 def test_allows_to_change_invalidation_of_inline_comments(
377 self, form_defaults, csrf_token, new_value):
376 self, form_defaults, csrf_token, new_value):
378 setting_key = 'use_outdated_comments'
377 setting_key = 'use_outdated_comments'
379 setting = SettingsModel().create_or_update_setting(
378 setting = SettingsModel().create_or_update_setting(
380 setting_key, not new_value, 'bool')
379 setting_key, not new_value, 'bool')
381 Session().add(setting)
380 Session().add(setting)
382 Session().commit()
381 Session().commit()
383
382
384 form_defaults.update({
383 form_defaults.update({
385 'csrf_token': csrf_token,
384 'csrf_token': csrf_token,
386 'rhodecode_use_outdated_comments': str(new_value),
385 'rhodecode_use_outdated_comments': str(new_value),
387 })
386 })
388 response = self.app.post(
387 response = self.app.post(
389 route_path('admin_settings_vcs_update'),
388 route_path('admin_settings_vcs_update'),
390 params=form_defaults,
389 params=form_defaults,
391 status=302)
390 status=302)
392 response = response.follow()
391 response = response.follow()
393 setting = SettingsModel().get_setting_by_name(setting_key)
392 setting = SettingsModel().get_setting_by_name(setting_key)
394 assert setting.app_settings_value is new_value
393 assert setting.app_settings_value is new_value
395
394
396 @pytest.mark.parametrize('new_value', [True, False])
395 @pytest.mark.parametrize('new_value', [True, False])
397 def test_allows_to_change_hg_rebase_merge_strategy(
396 def test_allows_to_change_hg_rebase_merge_strategy(
398 self, form_defaults, csrf_token, new_value):
397 self, form_defaults, csrf_token, new_value):
399 setting_key = 'hg_use_rebase_for_merging'
398 setting_key = 'hg_use_rebase_for_merging'
400
399
401 form_defaults.update({
400 form_defaults.update({
402 'csrf_token': csrf_token,
401 'csrf_token': csrf_token,
403 'rhodecode_' + setting_key: str(new_value),
402 'rhodecode_' + setting_key: str(new_value),
404 })
403 })
405
404
406 with mock.patch.dict(
405 with mock.patch.dict(
407 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
406 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
408 self.app.post(
407 self.app.post(
409 route_path('admin_settings_vcs_update'),
408 route_path('admin_settings_vcs_update'),
410 params=form_defaults,
409 params=form_defaults,
411 status=302)
410 status=302)
412
411
413 setting = SettingsModel().get_setting_by_name(setting_key)
412 setting = SettingsModel().get_setting_by_name(setting_key)
414 assert setting.app_settings_value is new_value
413 assert setting.app_settings_value is new_value
415
414
416 @pytest.fixture
415 @pytest.fixture
417 def disable_sql_cache(self, request):
416 def disable_sql_cache(self, request):
418 patcher = mock.patch(
417 patcher = mock.patch(
419 'rhodecode.lib.caching_query.FromCache.process_query')
418 'rhodecode.lib.caching_query.FromCache.process_query')
420 request.addfinalizer(patcher.stop)
419 request.addfinalizer(patcher.stop)
421 patcher.start()
420 patcher.start()
422
421
423 @pytest.fixture
422 @pytest.fixture
424 def form_defaults(self):
423 def form_defaults(self):
425 from rhodecode.apps.admin.views.settings import AdminSettingsView
424 from rhodecode.apps.admin.views.settings import AdminSettingsView
426 return AdminSettingsView._form_defaults()
425 return AdminSettingsView._form_defaults()
427
426
428 # TODO: johbo: What we really want is to checkpoint before a test run and
427 # TODO: johbo: What we really want is to checkpoint before a test run and
429 # reset the session afterwards.
428 # reset the session afterwards.
430 @pytest.fixture(scope='class', autouse=True)
429 @pytest.fixture(scope='class', autouse=True)
431 def cleanup_settings(self, request, baseapp):
430 def cleanup_settings(self, request, baseapp):
432 ui_id = RhodeCodeUi.ui_id
431 ui_id = RhodeCodeUi.ui_id
433 original_ids = list(
432 original_ids = list(
434 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
433 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
435
434
436 @request.addfinalizer
435 @request.addfinalizer
437 def cleanup():
436 def cleanup():
438 RhodeCodeUi.query().filter(
437 RhodeCodeUi.query().filter(
439 ui_id.notin_(original_ids)).delete(False)
438 ui_id.notin_(original_ids)).delete(False)
440
439
441
440
442 @pytest.mark.usefixtures('autologin_user', 'app')
441 @pytest.mark.usefixtures('autologin_user', 'app')
443 class TestLabsSettings(object):
442 class TestLabsSettings(object):
444 def test_get_settings_page_disabled(self):
443 def test_get_settings_page_disabled(self):
445 with mock.patch.dict(
444 with mock.patch.dict(
446 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
445 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
447
446
448 response = self.app.get(
447 response = self.app.get(
449 route_path('admin_settings_labs'), status=302)
448 route_path('admin_settings_labs'), status=302)
450
449
451 assert response.location.endswith(route_path('admin_settings'))
450 assert response.location.endswith(route_path('admin_settings'))
452
451
453 def test_get_settings_page_enabled(self):
452 def test_get_settings_page_enabled(self):
454 from rhodecode.apps.admin.views import settings
453 from rhodecode.apps.admin.views import settings
455 lab_settings = [
454 lab_settings = [
456 settings.LabSetting(
455 settings.LabSetting(
457 key='rhodecode_bool',
456 key='rhodecode_bool',
458 type='bool',
457 type='bool',
459 group='bool group',
458 group='bool group',
460 label='bool label',
459 label='bool label',
461 help='bool help'
460 help='bool help'
462 ),
461 ),
463 settings.LabSetting(
462 settings.LabSetting(
464 key='rhodecode_text',
463 key='rhodecode_text',
465 type='unicode',
464 type='unicode',
466 group='text group',
465 group='text group',
467 label='text label',
466 label='text label',
468 help='text help'
467 help='text help'
469 ),
468 ),
470 ]
469 ]
471 with mock.patch.dict(rhodecode.CONFIG,
470 with mock.patch.dict(rhodecode.CONFIG,
472 {'labs_settings_active': 'true'}):
471 {'labs_settings_active': 'true'}):
473 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
472 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
474 response = self.app.get(route_path('admin_settings_labs'))
473 response = self.app.get(route_path('admin_settings_labs'))
475
474
476 assert '<label>bool group:</label>' in response
475 assert '<label>bool group:</label>' in response
477 assert '<label for="rhodecode_bool">bool label</label>' in response
476 assert '<label for="rhodecode_bool">bool label</label>' in response
478 assert '<p class="help-block">bool help</p>' in response
477 assert '<p class="help-block">bool help</p>' in response
479 assert 'name="rhodecode_bool" type="checkbox"' in response
478 assert 'name="rhodecode_bool" type="checkbox"' in response
480
479
481 assert '<label>text group:</label>' in response
480 assert '<label>text group:</label>' in response
482 assert '<label for="rhodecode_text">text label</label>' in response
481 assert '<label for="rhodecode_text">text label</label>' in response
483 assert '<p class="help-block">text help</p>' in response
482 assert '<p class="help-block">text help</p>' in response
484 assert 'name="rhodecode_text" size="60" type="text"' in response
483 assert 'name="rhodecode_text" size="60" type="text"' in response
485
484
486
485
487 @pytest.mark.usefixtures('app')
486 @pytest.mark.usefixtures('app')
488 class TestOpenSourceLicenses(object):
487 class TestOpenSourceLicenses(object):
489
488
490 def test_records_are_displayed(self, autologin_user):
489 def test_records_are_displayed(self, autologin_user):
491 sample_licenses = [
490 sample_licenses = [
492 {
491 {
493 "license": [
492 "license": [
494 {
493 {
495 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
494 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
496 "shortName": "bsdOriginal",
495 "shortName": "bsdOriginal",
497 "spdxId": "BSD-4-Clause",
496 "spdxId": "BSD-4-Clause",
498 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
497 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
499 }
498 }
500 ],
499 ],
501 "name": "python2.7-coverage-3.7.1"
500 "name": "python2.7-coverage-3.7.1"
502 },
501 },
503 {
502 {
504 "license": [
503 "license": [
505 {
504 {
506 "fullName": "MIT License",
505 "fullName": "MIT License",
507 "shortName": "mit",
506 "shortName": "mit",
508 "spdxId": "MIT",
507 "spdxId": "MIT",
509 "url": "http://spdx.org/licenses/MIT.html"
508 "url": "http://spdx.org/licenses/MIT.html"
510 }
509 }
511 ],
510 ],
512 "name": "python2.7-bootstrapped-pip-9.0.1"
511 "name": "python2.7-bootstrapped-pip-9.0.1"
513 },
512 },
514 ]
513 ]
515 read_licenses_patch = mock.patch(
514 read_licenses_patch = mock.patch(
516 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
515 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
517 return_value=sample_licenses)
516 return_value=sample_licenses)
518 with read_licenses_patch:
517 with read_licenses_patch:
519 response = self.app.get(
518 response = self.app.get(
520 route_path('admin_settings_open_source'), status=200)
519 route_path('admin_settings_open_source'), status=200)
521
520
522 assert_response = AssertResponse(response)
521 assert_response = AssertResponse(response)
523 assert_response.element_contains(
522 assert_response.element_contains(
524 '.panel-heading', 'Licenses of Third Party Packages')
523 '.panel-heading', 'Licenses of Third Party Packages')
525 for license_data in sample_licenses:
524 for license_data in sample_licenses:
526 response.mustcontain(license_data["license"][0]["spdxId"])
525 response.mustcontain(license_data["license"][0]["spdxId"])
527 assert_response.element_contains('.panel-body', license_data["name"])
526 assert_response.element_contains('.panel-body', license_data["name"])
528
527
529 def test_records_can_be_read(self, autologin_user):
528 def test_records_can_be_read(self, autologin_user):
530 response = self.app.get(
529 response = self.app.get(
531 route_path('admin_settings_open_source'), status=200)
530 route_path('admin_settings_open_source'), status=200)
532 assert_response = AssertResponse(response)
531 assert_response = AssertResponse(response)
533 assert_response.element_contains(
532 assert_response.element_contains(
534 '.panel-heading', 'Licenses of Third Party Packages')
533 '.panel-heading', 'Licenses of Third Party Packages')
535
534
536 def test_forbidden_when_normal_user(self, autologin_regular_user):
535 def test_forbidden_when_normal_user(self, autologin_regular_user):
537 self.app.get(
536 self.app.get(
538 route_path('admin_settings_open_source'), status=404)
537 route_path('admin_settings_open_source'), status=404)
539
538
540
539
541 @pytest.mark.usefixtures('app')
540 @pytest.mark.usefixtures('app')
542 class TestUserSessions(object):
541 class TestUserSessions(object):
543
542
544 def test_forbidden_when_normal_user(self, autologin_regular_user):
543 def test_forbidden_when_normal_user(self, autologin_regular_user):
545 self.app.get(route_path('admin_settings_sessions'), status=404)
544 self.app.get(route_path('admin_settings_sessions'), status=404)
546
545
547 def test_show_sessions_page(self, autologin_user):
546 def test_show_sessions_page(self, autologin_user):
548 response = self.app.get(route_path('admin_settings_sessions'), status=200)
547 response = self.app.get(route_path('admin_settings_sessions'), status=200)
549 response.mustcontain('file')
548 response.mustcontain('file')
550
549
551 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
550 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
552
551
553 post_data = {
552 post_data = {
554 'csrf_token': csrf_token,
553 'csrf_token': csrf_token,
555 'expire_days': '60'
554 'expire_days': '60'
556 }
555 }
557 response = self.app.post(
556 response = self.app.post(
558 route_path('admin_settings_sessions_cleanup'), params=post_data,
557 route_path('admin_settings_sessions_cleanup'), params=post_data,
559 status=302)
558 status=302)
560 assert_session_flash(response, 'Cleaned up old sessions')
559 assert_session_flash(response, 'Cleaned up old sessions')
561
560
562
561
563 @pytest.mark.usefixtures('app')
562 @pytest.mark.usefixtures('app')
564 class TestAdminSystemInfo(object):
563 class TestAdminSystemInfo(object):
565
564
566 def test_forbidden_when_normal_user(self, autologin_regular_user):
565 def test_forbidden_when_normal_user(self, autologin_regular_user):
567 self.app.get(route_path('admin_settings_system'), status=404)
566 self.app.get(route_path('admin_settings_system'), status=404)
568
567
569 def test_system_info_page(self, autologin_user):
568 def test_system_info_page(self, autologin_user):
570 response = self.app.get(route_path('admin_settings_system'))
569 response = self.app.get(route_path('admin_settings_system'))
571 response.mustcontain('RhodeCode Community Edition, version {}'.format(
570 response.mustcontain('RhodeCode Community Edition, version {}'.format(
572 rhodecode.__version__))
571 rhodecode.__version__))
573
572
574 def test_system_update_new_version(self, autologin_user):
573 def test_system_update_new_version(self, autologin_user):
575 update_data = {
574 update_data = {
576 'versions': [
575 'versions': [
577 {
576 {
578 'version': '100.3.1415926535',
577 'version': '100.3.1415926535',
579 'general': 'The latest version we are ever going to ship'
578 'general': 'The latest version we are ever going to ship'
580 },
579 },
581 {
580 {
582 'version': '0.0.0',
581 'version': '0.0.0',
583 'general': 'The first version we ever shipped'
582 'general': 'The first version we ever shipped'
584 }
583 }
585 ]
584 ]
586 }
585 }
587 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
586 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
588 response = self.app.get(route_path('admin_settings_system_update'))
587 response = self.app.get(route_path('admin_settings_system_update'))
589 response.mustcontain('A <b>new version</b> is available')
588 response.mustcontain('A <b>new version</b> is available')
590
589
591 def test_system_update_nothing_new(self, autologin_user):
590 def test_system_update_nothing_new(self, autologin_user):
592 update_data = {
591 update_data = {
593 'versions': [
592 'versions': [
594 {
593 {
595 'version': '0.0.0',
594 'version': '0.0.0',
596 'general': 'The first version we ever shipped'
595 'general': 'The first version we ever shipped'
597 }
596 }
598 ]
597 ]
599 }
598 }
600 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
599 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
601 response = self.app.get(route_path('admin_settings_system_update'))
600 response = self.app.get(route_path('admin_settings_system_update'))
602 response.mustcontain(
601 response.mustcontain(
603 'This instance is already running the <b>latest</b> stable version')
602 'This instance is already running the <b>latest</b> stable version')
604
603
605 def test_system_update_bad_response(self, autologin_user):
604 def test_system_update_bad_response(self, autologin_user):
606 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
605 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
607 response = self.app.get(route_path('admin_settings_system_update'))
606 response = self.app.get(route_path('admin_settings_system_update'))
608 response.mustcontain(
607 response.mustcontain(
609 'Bad data sent from update server')
608 'Bad data sent from update server')
610
609
611
610
612 @pytest.mark.usefixtures("app")
611 @pytest.mark.usefixtures("app")
613 class TestAdminSettingsIssueTracker(object):
612 class TestAdminSettingsIssueTracker(object):
614 RC_PREFIX = 'rhodecode_'
613 RC_PREFIX = 'rhodecode_'
615 SHORT_PATTERN_KEY = 'issuetracker_pat_'
614 SHORT_PATTERN_KEY = 'issuetracker_pat_'
616 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
615 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
617
616
618 def test_issuetracker_index(self, autologin_user):
617 def test_issuetracker_index(self, autologin_user):
619 response = self.app.get(route_path('admin_settings_issuetracker'))
618 response = self.app.get(route_path('admin_settings_issuetracker'))
620 assert response.status_code == 200
619 assert response.status_code == 200
621
620
622 def test_add_empty_issuetracker_pattern(
621 def test_add_empty_issuetracker_pattern(
623 self, request, autologin_user, csrf_token):
622 self, request, autologin_user, csrf_token):
624 post_url = route_path('admin_settings_issuetracker_update')
623 post_url = route_path('admin_settings_issuetracker_update')
625 post_data = {
624 post_data = {
626 'csrf_token': csrf_token
625 'csrf_token': csrf_token
627 }
626 }
628 self.app.post(post_url, post_data, status=302)
627 self.app.post(post_url, post_data, status=302)
629
628
630 def test_add_issuetracker_pattern(
629 def test_add_issuetracker_pattern(
631 self, request, autologin_user, csrf_token):
630 self, request, autologin_user, csrf_token):
632 pattern = 'issuetracker_pat'
631 pattern = 'issuetracker_pat'
633 another_pattern = pattern+'1'
632 another_pattern = pattern+'1'
634 post_url = route_path('admin_settings_issuetracker_update')
633 post_url = route_path('admin_settings_issuetracker_update')
635 post_data = {
634 post_data = {
636 'new_pattern_pattern_0': pattern,
635 'new_pattern_pattern_0': pattern,
637 'new_pattern_url_0': 'http://url',
636 'new_pattern_url_0': 'http://url',
638 'new_pattern_prefix_0': 'prefix',
637 'new_pattern_prefix_0': 'prefix',
639 'new_pattern_description_0': 'description',
638 'new_pattern_description_0': 'description',
640 'new_pattern_pattern_1': another_pattern,
639 'new_pattern_pattern_1': another_pattern,
641 'new_pattern_url_1': 'https://url1',
640 'new_pattern_url_1': 'https://url1',
642 'new_pattern_prefix_1': 'prefix1',
641 'new_pattern_prefix_1': 'prefix1',
643 'new_pattern_description_1': 'description1',
642 'new_pattern_description_1': 'description1',
644 'csrf_token': csrf_token
643 'csrf_token': csrf_token
645 }
644 }
646 self.app.post(post_url, post_data, status=302)
645 self.app.post(post_url, post_data, status=302)
647 settings = SettingsModel().get_all_settings()
646 settings = SettingsModel().get_all_settings()
648 self.uid = md5(pattern)
647 self.uid = md5(pattern)
649 assert settings[self.PATTERN_KEY+self.uid] == pattern
648 assert settings[self.PATTERN_KEY+self.uid] == pattern
650 self.another_uid = md5(another_pattern)
649 self.another_uid = md5(another_pattern)
651 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
650 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
652
651
653 @request.addfinalizer
652 @request.addfinalizer
654 def cleanup():
653 def cleanup():
655 defaults = SettingsModel().get_all_settings()
654 defaults = SettingsModel().get_all_settings()
656
655
657 entries = [name for name in defaults if (
656 entries = [name for name in defaults if (
658 (self.uid in name) or (self.another_uid) in name)]
657 (self.uid in name) or (self.another_uid) in name)]
659 start = len(self.RC_PREFIX)
658 start = len(self.RC_PREFIX)
660 for del_key in entries:
659 for del_key in entries:
661 # TODO: anderson: get_by_name needs name without prefix
660 # TODO: anderson: get_by_name needs name without prefix
662 entry = SettingsModel().get_setting_by_name(del_key[start:])
661 entry = SettingsModel().get_setting_by_name(del_key[start:])
663 Session().delete(entry)
662 Session().delete(entry)
664
663
665 Session().commit()
664 Session().commit()
666
665
667 def test_edit_issuetracker_pattern(
666 def test_edit_issuetracker_pattern(
668 self, autologin_user, backend, csrf_token, request):
667 self, autologin_user, backend, csrf_token, request):
669 old_pattern = 'issuetracker_pat'
668 old_pattern = 'issuetracker_pat'
670 old_uid = md5(old_pattern)
669 old_uid = md5(old_pattern)
671 pattern = 'issuetracker_pat_new'
670 pattern = 'issuetracker_pat_new'
672 self.new_uid = md5(pattern)
671 self.new_uid = md5(pattern)
673
672
674 SettingsModel().create_or_update_setting(
673 SettingsModel().create_or_update_setting(
675 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
674 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
676
675
677 post_url = route_path('admin_settings_issuetracker_update')
676 post_url = route_path('admin_settings_issuetracker_update')
678 post_data = {
677 post_data = {
679 'new_pattern_pattern_0': pattern,
678 'new_pattern_pattern_0': pattern,
680 'new_pattern_url_0': 'https://url',
679 'new_pattern_url_0': 'https://url',
681 'new_pattern_prefix_0': 'prefix',
680 'new_pattern_prefix_0': 'prefix',
682 'new_pattern_description_0': 'description',
681 'new_pattern_description_0': 'description',
683 'uid': old_uid,
682 'uid': old_uid,
684 'csrf_token': csrf_token
683 'csrf_token': csrf_token
685 }
684 }
686 self.app.post(post_url, post_data, status=302)
685 self.app.post(post_url, post_data, status=302)
687 settings = SettingsModel().get_all_settings()
686 settings = SettingsModel().get_all_settings()
688 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
687 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
689 assert self.PATTERN_KEY+old_uid not in settings
688 assert self.PATTERN_KEY+old_uid not in settings
690
689
691 @request.addfinalizer
690 @request.addfinalizer
692 def cleanup():
691 def cleanup():
693 IssueTrackerSettingsModel().delete_entries(self.new_uid)
692 IssueTrackerSettingsModel().delete_entries(self.new_uid)
694
693
695 def test_replace_issuetracker_pattern_description(
694 def test_replace_issuetracker_pattern_description(
696 self, autologin_user, csrf_token, request, settings_util):
695 self, autologin_user, csrf_token, request, settings_util):
697 prefix = 'issuetracker'
696 prefix = 'issuetracker'
698 pattern = 'issuetracker_pat'
697 pattern = 'issuetracker_pat'
699 self.uid = md5(pattern)
698 self.uid = md5(pattern)
700 pattern_key = '_'.join([prefix, 'pat', self.uid])
699 pattern_key = '_'.join([prefix, 'pat', self.uid])
701 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
700 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
702 desc_key = '_'.join([prefix, 'desc', self.uid])
701 desc_key = '_'.join([prefix, 'desc', self.uid])
703 rc_desc_key = '_'.join(['rhodecode', desc_key])
702 rc_desc_key = '_'.join(['rhodecode', desc_key])
704 new_description = 'new_description'
703 new_description = 'new_description'
705
704
706 settings_util.create_rhodecode_setting(
705 settings_util.create_rhodecode_setting(
707 pattern_key, pattern, 'unicode', cleanup=False)
706 pattern_key, pattern, 'unicode', cleanup=False)
708 settings_util.create_rhodecode_setting(
707 settings_util.create_rhodecode_setting(
709 desc_key, 'old description', 'unicode', cleanup=False)
708 desc_key, 'old description', 'unicode', cleanup=False)
710
709
711 post_url = route_path('admin_settings_issuetracker_update')
710 post_url = route_path('admin_settings_issuetracker_update')
712 post_data = {
711 post_data = {
713 'new_pattern_pattern_0': pattern,
712 'new_pattern_pattern_0': pattern,
714 'new_pattern_url_0': 'https://url',
713 'new_pattern_url_0': 'https://url',
715 'new_pattern_prefix_0': 'prefix',
714 'new_pattern_prefix_0': 'prefix',
716 'new_pattern_description_0': new_description,
715 'new_pattern_description_0': new_description,
717 'uid': self.uid,
716 'uid': self.uid,
718 'csrf_token': csrf_token
717 'csrf_token': csrf_token
719 }
718 }
720 self.app.post(post_url, post_data, status=302)
719 self.app.post(post_url, post_data, status=302)
721 settings = SettingsModel().get_all_settings()
720 settings = SettingsModel().get_all_settings()
722 assert settings[rc_pattern_key] == pattern
721 assert settings[rc_pattern_key] == pattern
723 assert settings[rc_desc_key] == new_description
722 assert settings[rc_desc_key] == new_description
724
723
725 @request.addfinalizer
724 @request.addfinalizer
726 def cleanup():
725 def cleanup():
727 IssueTrackerSettingsModel().delete_entries(self.uid)
726 IssueTrackerSettingsModel().delete_entries(self.uid)
728
727
729 def test_delete_issuetracker_pattern(
728 def test_delete_issuetracker_pattern(
730 self, autologin_user, backend, csrf_token, settings_util):
729 self, autologin_user, backend, csrf_token, settings_util):
731 pattern = 'issuetracker_pat'
730 pattern = 'issuetracker_pat'
732 uid = md5(pattern)
731 uid = md5(pattern)
733 settings_util.create_rhodecode_setting(
732 settings_util.create_rhodecode_setting(
734 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
733 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
735
734
736 post_url = route_path('admin_settings_issuetracker_delete')
735 post_url = route_path('admin_settings_issuetracker_delete')
737 post_data = {
736 post_data = {
738 '_method': 'delete',
737 '_method': 'delete',
739 'uid': uid,
738 'uid': uid,
740 'csrf_token': csrf_token
739 'csrf_token': csrf_token
741 }
740 }
742 self.app.post(post_url, post_data, status=302)
741 self.app.post(post_url, post_data, status=302)
743 settings = SettingsModel().get_all_settings()
742 settings = SettingsModel().get_all_settings()
744 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
743 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
@@ -1,2474 +1,2478 b''
1 //Primary CSS
1 //Primary CSS
2
2
3 //--- IMPORTS ------------------//
3 //--- IMPORTS ------------------//
4
4
5 @import 'helpers';
5 @import 'helpers';
6 @import 'mixins';
6 @import 'mixins';
7 @import 'rcicons';
7 @import 'rcicons';
8 @import 'variables';
8 @import 'variables';
9 @import 'bootstrap-variables';
9 @import 'bootstrap-variables';
10 @import 'form-bootstrap';
10 @import 'form-bootstrap';
11 @import 'codemirror';
11 @import 'codemirror';
12 @import 'legacy_code_styles';
12 @import 'legacy_code_styles';
13 @import 'readme-box';
13 @import 'readme-box';
14 @import 'progress-bar';
14 @import 'progress-bar';
15
15
16 @import 'type';
16 @import 'type';
17 @import 'alerts';
17 @import 'alerts';
18 @import 'buttons';
18 @import 'buttons';
19 @import 'tags';
19 @import 'tags';
20 @import 'code-block';
20 @import 'code-block';
21 @import 'examples';
21 @import 'examples';
22 @import 'login';
22 @import 'login';
23 @import 'main-content';
23 @import 'main-content';
24 @import 'select2';
24 @import 'select2';
25 @import 'comments';
25 @import 'comments';
26 @import 'panels-bootstrap';
26 @import 'panels-bootstrap';
27 @import 'panels';
27 @import 'panels';
28 @import 'deform';
28 @import 'deform';
29
29
30 //--- BASE ------------------//
30 //--- BASE ------------------//
31 .noscript-error {
31 .noscript-error {
32 top: 0;
32 top: 0;
33 left: 0;
33 left: 0;
34 width: 100%;
34 width: 100%;
35 z-index: 101;
35 z-index: 101;
36 text-align: center;
36 text-align: center;
37 font-size: 120%;
37 font-size: 120%;
38 color: white;
38 color: white;
39 background-color: @alert2;
39 background-color: @alert2;
40 padding: 5px 0 5px 0;
40 padding: 5px 0 5px 0;
41 font-weight: @text-semibold-weight;
41 font-weight: @text-semibold-weight;
42 font-family: @text-semibold;
42 font-family: @text-semibold;
43 }
43 }
44
44
45 html {
45 html {
46 display: table;
46 display: table;
47 height: 100%;
47 height: 100%;
48 width: 100%;
48 width: 100%;
49 }
49 }
50
50
51 body {
51 body {
52 display: table-cell;
52 display: table-cell;
53 width: 100%;
53 width: 100%;
54 }
54 }
55
55
56 //--- LAYOUT ------------------//
56 //--- LAYOUT ------------------//
57
57
58 .hidden{
58 .hidden{
59 display: none !important;
59 display: none !important;
60 }
60 }
61
61
62 .box{
62 .box{
63 float: left;
63 float: left;
64 width: 100%;
64 width: 100%;
65 }
65 }
66
66
67 .browser-header {
67 .browser-header {
68 clear: both;
68 clear: both;
69 }
69 }
70 .main {
70 .main {
71 clear: both;
71 clear: both;
72 padding:0 0 @pagepadding;
72 padding:0 0 @pagepadding;
73 height: auto;
73 height: auto;
74
74
75 &:after { //clearfix
75 &:after { //clearfix
76 content:"";
76 content:"";
77 clear:both;
77 clear:both;
78 width:100%;
78 width:100%;
79 display:block;
79 display:block;
80 }
80 }
81 }
81 }
82
82
83 .action-link{
83 .action-link{
84 margin-left: @padding;
84 margin-left: @padding;
85 padding-left: @padding;
85 padding-left: @padding;
86 border-left: @border-thickness solid @border-default-color;
86 border-left: @border-thickness solid @border-default-color;
87 }
87 }
88
88
89 input + .action-link, .action-link.first{
89 input + .action-link, .action-link.first{
90 border-left: none;
90 border-left: none;
91 }
91 }
92
92
93 .action-link.last{
93 .action-link.last{
94 margin-right: @padding;
94 margin-right: @padding;
95 padding-right: @padding;
95 padding-right: @padding;
96 }
96 }
97
97
98 .action-link.active,
98 .action-link.active,
99 .action-link.active a{
99 .action-link.active a{
100 color: @grey4;
100 color: @grey4;
101 }
101 }
102
102
103 .action-link.disabled {
103 .action-link.disabled {
104 color: @grey4;
104 color: @grey4;
105 cursor: inherit;
105 cursor: inherit;
106 }
106 }
107
107
108 .clipboard-action {
108 .clipboard-action {
109 cursor: pointer;
109 cursor: pointer;
110 }
110 }
111
111
112 ul.simple-list{
112 ul.simple-list{
113 list-style: none;
113 list-style: none;
114 margin: 0;
114 margin: 0;
115 padding: 0;
115 padding: 0;
116 }
116 }
117
117
118 .main-content {
118 .main-content {
119 padding-bottom: @pagepadding;
119 padding-bottom: @pagepadding;
120 }
120 }
121
121
122 .wide-mode-wrapper {
122 .wide-mode-wrapper {
123 max-width:4000px !important;
123 max-width:4000px !important;
124 }
124 }
125
125
126 .wrapper {
126 .wrapper {
127 position: relative;
127 position: relative;
128 max-width: @wrapper-maxwidth;
128 max-width: @wrapper-maxwidth;
129 margin: 0 auto;
129 margin: 0 auto;
130 }
130 }
131
131
132 #content {
132 #content {
133 clear: both;
133 clear: both;
134 padding: 0 @contentpadding;
134 padding: 0 @contentpadding;
135 }
135 }
136
136
137 .advanced-settings-fields{
137 .advanced-settings-fields{
138 input{
138 input{
139 margin-left: @textmargin;
139 margin-left: @textmargin;
140 margin-right: @padding/2;
140 margin-right: @padding/2;
141 }
141 }
142 }
142 }
143
143
144 .cs_files_title {
144 .cs_files_title {
145 margin: @pagepadding 0 0;
145 margin: @pagepadding 0 0;
146 }
146 }
147
147
148 input.inline[type="file"] {
148 input.inline[type="file"] {
149 display: inline;
149 display: inline;
150 }
150 }
151
151
152 .error_page {
152 .error_page {
153 margin: 10% auto;
153 margin: 10% auto;
154
154
155 h1 {
155 h1 {
156 color: @grey2;
156 color: @grey2;
157 }
157 }
158
158
159 .alert {
159 .alert {
160 margin: @padding 0;
160 margin: @padding 0;
161 }
161 }
162
162
163 .error-branding {
163 .error-branding {
164 color: @grey4;
164 color: @grey4;
165 font-weight: @text-semibold-weight;
165 font-weight: @text-semibold-weight;
166 font-family: @text-semibold;
166 font-family: @text-semibold;
167 }
167 }
168
168
169 .error_message {
169 .error_message {
170 font-family: @text-regular;
170 font-family: @text-regular;
171 }
171 }
172
172
173 .sidebar {
173 .sidebar {
174 min-height: 275px;
174 min-height: 275px;
175 margin: 0;
175 margin: 0;
176 padding: 0 0 @sidebarpadding @sidebarpadding;
176 padding: 0 0 @sidebarpadding @sidebarpadding;
177 border: none;
177 border: none;
178 }
178 }
179
179
180 .main-content {
180 .main-content {
181 position: relative;
181 position: relative;
182 margin: 0 @sidebarpadding @sidebarpadding;
182 margin: 0 @sidebarpadding @sidebarpadding;
183 padding: 0 0 0 @sidebarpadding;
183 padding: 0 0 0 @sidebarpadding;
184 border-left: @border-thickness solid @grey5;
184 border-left: @border-thickness solid @grey5;
185
185
186 @media (max-width:767px) {
186 @media (max-width:767px) {
187 clear: both;
187 clear: both;
188 width: 100%;
188 width: 100%;
189 margin: 0;
189 margin: 0;
190 border: none;
190 border: none;
191 }
191 }
192 }
192 }
193
193
194 .inner-column {
194 .inner-column {
195 float: left;
195 float: left;
196 width: 29.75%;
196 width: 29.75%;
197 min-height: 150px;
197 min-height: 150px;
198 margin: @sidebarpadding 2% 0 0;
198 margin: @sidebarpadding 2% 0 0;
199 padding: 0 2% 0 0;
199 padding: 0 2% 0 0;
200 border-right: @border-thickness solid @grey5;
200 border-right: @border-thickness solid @grey5;
201
201
202 @media (max-width:767px) {
202 @media (max-width:767px) {
203 clear: both;
203 clear: both;
204 width: 100%;
204 width: 100%;
205 border: none;
205 border: none;
206 }
206 }
207
207
208 ul {
208 ul {
209 padding-left: 1.25em;
209 padding-left: 1.25em;
210 }
210 }
211
211
212 &:last-child {
212 &:last-child {
213 margin: @sidebarpadding 0 0;
213 margin: @sidebarpadding 0 0;
214 border: none;
214 border: none;
215 }
215 }
216
216
217 h4 {
217 h4 {
218 margin: 0 0 @padding;
218 margin: 0 0 @padding;
219 font-weight: @text-semibold-weight;
219 font-weight: @text-semibold-weight;
220 font-family: @text-semibold;
220 font-family: @text-semibold;
221 }
221 }
222 }
222 }
223 }
223 }
224 .error-page-logo {
224 .error-page-logo {
225 width: 130px;
225 width: 130px;
226 height: 160px;
226 height: 160px;
227 }
227 }
228
228
229 // HEADER
229 // HEADER
230 .header {
230 .header {
231
231
232 // TODO: johbo: Fix login pages, so that they work without a min-height
232 // TODO: johbo: Fix login pages, so that they work without a min-height
233 // for the header and then remove the min-height. I chose a smaller value
233 // for the header and then remove the min-height. I chose a smaller value
234 // intentionally here to avoid rendering issues in the main navigation.
234 // intentionally here to avoid rendering issues in the main navigation.
235 min-height: 49px;
235 min-height: 49px;
236
236
237 position: relative;
237 position: relative;
238 vertical-align: bottom;
238 vertical-align: bottom;
239 padding: 0 @header-padding;
239 padding: 0 @header-padding;
240 background-color: @grey2;
240 background-color: @grey2;
241 color: @grey5;
241 color: @grey5;
242
242
243 .title {
243 .title {
244 overflow: visible;
244 overflow: visible;
245 }
245 }
246
246
247 &:before,
247 &:before,
248 &:after {
248 &:after {
249 content: "";
249 content: "";
250 clear: both;
250 clear: both;
251 width: 100%;
251 width: 100%;
252 }
252 }
253
253
254 // TODO: johbo: Avoids breaking "Repositories" chooser
254 // TODO: johbo: Avoids breaking "Repositories" chooser
255 .select2-container .select2-choice .select2-arrow {
255 .select2-container .select2-choice .select2-arrow {
256 display: none;
256 display: none;
257 }
257 }
258 }
258 }
259
259
260 #header-inner {
260 #header-inner {
261 &.title {
261 &.title {
262 margin: 0;
262 margin: 0;
263 }
263 }
264 &:before,
264 &:before,
265 &:after {
265 &:after {
266 content: "";
266 content: "";
267 clear: both;
267 clear: both;
268 }
268 }
269 }
269 }
270
270
271 // Gists
271 // Gists
272 #files_data {
272 #files_data {
273 clear: both; //for firefox
273 clear: both; //for firefox
274 }
274 }
275 #gistid {
275 #gistid {
276 margin-right: @padding;
276 margin-right: @padding;
277 }
277 }
278
278
279 // Global Settings Editor
279 // Global Settings Editor
280 .textarea.editor {
280 .textarea.editor {
281 float: left;
281 float: left;
282 position: relative;
282 position: relative;
283 max-width: @texteditor-width;
283 max-width: @texteditor-width;
284
284
285 select {
285 select {
286 position: absolute;
286 position: absolute;
287 top:10px;
287 top:10px;
288 right:0;
288 right:0;
289 }
289 }
290
290
291 .CodeMirror {
291 .CodeMirror {
292 margin: 0;
292 margin: 0;
293 }
293 }
294
294
295 .help-block {
295 .help-block {
296 margin: 0 0 @padding;
296 margin: 0 0 @padding;
297 padding:.5em;
297 padding:.5em;
298 background-color: @grey6;
298 background-color: @grey6;
299 &.pre-formatting {
299 &.pre-formatting {
300 white-space: pre;
300 white-space: pre;
301 }
301 }
302 }
302 }
303 }
303 }
304
304
305 ul.auth_plugins {
305 ul.auth_plugins {
306 margin: @padding 0 @padding @legend-width;
306 margin: @padding 0 @padding @legend-width;
307 padding: 0;
307 padding: 0;
308
308
309 li {
309 li {
310 margin-bottom: @padding;
310 margin-bottom: @padding;
311 line-height: 1em;
311 line-height: 1em;
312 list-style-type: none;
312 list-style-type: none;
313
313
314 .auth_buttons .btn {
314 .auth_buttons .btn {
315 margin-right: @padding;
315 margin-right: @padding;
316 }
316 }
317
317
318 }
318 }
319 }
319 }
320
320
321
321
322 // My Account PR list
322 // My Account PR list
323
323
324 #show_closed {
324 #show_closed {
325 margin: 0 1em 0 0;
325 margin: 0 1em 0 0;
326 }
326 }
327
327
328 .pullrequestlist {
328 .pullrequestlist {
329 .closed {
329 .closed {
330 background-color: @grey6;
330 background-color: @grey6;
331 }
331 }
332 .td-status {
332 .td-status {
333 padding-left: .5em;
333 padding-left: .5em;
334 }
334 }
335 .log-container .truncate {
335 .log-container .truncate {
336 height: 2.75em;
336 height: 2.75em;
337 white-space: pre-line;
337 white-space: pre-line;
338 }
338 }
339 table.rctable .user {
339 table.rctable .user {
340 padding-left: 0;
340 padding-left: 0;
341 }
341 }
342 table.rctable {
342 table.rctable {
343 td.td-description,
343 td.td-description,
344 .rc-user {
344 .rc-user {
345 min-width: auto;
345 min-width: auto;
346 }
346 }
347 }
347 }
348 }
348 }
349
349
350 // Pull Requests
350 // Pull Requests
351
351
352 .pullrequests_section_head {
352 .pullrequests_section_head {
353 display: block;
353 display: block;
354 clear: both;
354 clear: both;
355 margin: @padding 0;
355 margin: @padding 0;
356 font-weight: @text-bold-weight;
356 font-weight: @text-bold-weight;
357 font-family: @text-bold;
357 font-family: @text-bold;
358 }
358 }
359
359
360 .pr-origininfo, .pr-targetinfo {
360 .pr-origininfo, .pr-targetinfo {
361 position: relative;
361 position: relative;
362
362
363 .tag {
363 .tag {
364 display: inline-block;
364 display: inline-block;
365 margin: 0 1em .5em 0;
365 margin: 0 1em .5em 0;
366 }
366 }
367
367
368 .clone-url {
368 .clone-url {
369 display: inline-block;
369 display: inline-block;
370 margin: 0 0 .5em 0;
370 margin: 0 0 .5em 0;
371 padding: 0;
371 padding: 0;
372 line-height: 1.2em;
372 line-height: 1.2em;
373 }
373 }
374 }
374 }
375
375
376 .pr-mergeinfo {
376 .pr-mergeinfo {
377 min-width: 95% !important;
377 min-width: 95% !important;
378 padding: 0 !important;
378 padding: 0 !important;
379 border: 0;
379 border: 0;
380 }
380 }
381 .pr-mergeinfo-copy {
381 .pr-mergeinfo-copy {
382 padding: 0 0;
382 padding: 0 0;
383 }
383 }
384
384
385 .pr-pullinfo {
385 .pr-pullinfo {
386 min-width: 95% !important;
386 min-width: 95% !important;
387 padding: 0 !important;
387 padding: 0 !important;
388 border: 0;
388 border: 0;
389 }
389 }
390 .pr-pullinfo-copy {
390 .pr-pullinfo-copy {
391 padding: 0 0;
391 padding: 0 0;
392 }
392 }
393
393
394
394
395 #pr-title-input {
395 #pr-title-input {
396 width: 72%;
396 width: 72%;
397 font-size: 1em;
397 font-size: 1em;
398 margin: 0;
398 margin: 0;
399 padding: 0 0 0 @padding/4;
399 padding: 0 0 0 @padding/4;
400 line-height: 1.7em;
400 line-height: 1.7em;
401 color: @text-color;
401 color: @text-color;
402 letter-spacing: .02em;
402 letter-spacing: .02em;
403 font-weight: @text-bold-weight;
403 font-weight: @text-bold-weight;
404 font-family: @text-bold;
404 font-family: @text-bold;
405 }
405 }
406
406
407 #pullrequest_title {
407 #pullrequest_title {
408 width: 100%;
408 width: 100%;
409 box-sizing: border-box;
409 box-sizing: border-box;
410 }
410 }
411
411
412 #pr_open_message {
412 #pr_open_message {
413 border: @border-thickness solid #fff;
413 border: @border-thickness solid #fff;
414 border-radius: @border-radius;
414 border-radius: @border-radius;
415 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
415 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
416 text-align: left;
416 text-align: left;
417 overflow: hidden;
417 overflow: hidden;
418 }
418 }
419
419
420 .pr-submit-button {
420 .pr-submit-button {
421 float: right;
421 float: right;
422 margin: 0 0 0 5px;
422 margin: 0 0 0 5px;
423 }
423 }
424
424
425 .pr-spacing-container {
425 .pr-spacing-container {
426 padding: 20px;
426 padding: 20px;
427 clear: both
427 clear: both
428 }
428 }
429
429
430 #pr-description-input {
430 #pr-description-input {
431 margin-bottom: 0;
431 margin-bottom: 0;
432 }
432 }
433
433
434 .pr-description-label {
434 .pr-description-label {
435 vertical-align: top;
435 vertical-align: top;
436 }
436 }
437
437
438 .perms_section_head {
438 .perms_section_head {
439 min-width: 625px;
439 min-width: 625px;
440
440
441 h2 {
441 h2 {
442 margin-bottom: 0;
442 margin-bottom: 0;
443 }
443 }
444
444
445 .label-checkbox {
445 .label-checkbox {
446 float: left;
446 float: left;
447 }
447 }
448
448
449 &.field {
449 &.field {
450 margin: @space 0 @padding;
450 margin: @space 0 @padding;
451 }
451 }
452
452
453 &:first-child.field {
453 &:first-child.field {
454 margin-top: 0;
454 margin-top: 0;
455
455
456 .label {
456 .label {
457 margin-top: 0;
457 margin-top: 0;
458 padding-top: 0;
458 padding-top: 0;
459 }
459 }
460
460
461 .radios {
461 .radios {
462 padding-top: 0;
462 padding-top: 0;
463 }
463 }
464 }
464 }
465
465
466 .radios {
466 .radios {
467 position: relative;
467 position: relative;
468 width: 505px;
468 width: 505px;
469 }
469 }
470 }
470 }
471
471
472 //--- MODULES ------------------//
472 //--- MODULES ------------------//
473
473
474
474
475 // Server Announcement
475 // Server Announcement
476 #server-announcement {
476 #server-announcement {
477 width: 95%;
477 width: 95%;
478 margin: @padding auto;
478 margin: @padding auto;
479 padding: @padding;
479 padding: @padding;
480 border-width: 2px;
480 border-width: 2px;
481 border-style: solid;
481 border-style: solid;
482 .border-radius(2px);
482 .border-radius(2px);
483 font-weight: @text-bold-weight;
483 font-weight: @text-bold-weight;
484 font-family: @text-bold;
484 font-family: @text-bold;
485
485
486 &.info { border-color: @alert4; background-color: @alert4-inner; }
486 &.info { border-color: @alert4; background-color: @alert4-inner; }
487 &.warning { border-color: @alert3; background-color: @alert3-inner; }
487 &.warning { border-color: @alert3; background-color: @alert3-inner; }
488 &.error { border-color: @alert2; background-color: @alert2-inner; }
488 &.error { border-color: @alert2; background-color: @alert2-inner; }
489 &.success { border-color: @alert1; background-color: @alert1-inner; }
489 &.success { border-color: @alert1; background-color: @alert1-inner; }
490 &.neutral { border-color: @grey3; background-color: @grey6; }
490 &.neutral { border-color: @grey3; background-color: @grey6; }
491 }
491 }
492
492
493 // Fixed Sidebar Column
493 // Fixed Sidebar Column
494 .sidebar-col-wrapper {
494 .sidebar-col-wrapper {
495 padding-left: @sidebar-all-width;
495 padding-left: @sidebar-all-width;
496
496
497 .sidebar {
497 .sidebar {
498 width: @sidebar-width;
498 width: @sidebar-width;
499 margin-left: -@sidebar-all-width;
499 margin-left: -@sidebar-all-width;
500 }
500 }
501 }
501 }
502
502
503 .sidebar-col-wrapper.scw-small {
503 .sidebar-col-wrapper.scw-small {
504 padding-left: @sidebar-small-all-width;
504 padding-left: @sidebar-small-all-width;
505
505
506 .sidebar {
506 .sidebar {
507 width: @sidebar-small-width;
507 width: @sidebar-small-width;
508 margin-left: -@sidebar-small-all-width;
508 margin-left: -@sidebar-small-all-width;
509 }
509 }
510 }
510 }
511
511
512
512
513 // FOOTER
513 // FOOTER
514 #footer {
514 #footer {
515 padding: 0;
515 padding: 0;
516 text-align: center;
516 text-align: center;
517 vertical-align: middle;
517 vertical-align: middle;
518 color: @grey2;
518 color: @grey2;
519 background-color: @grey6;
519 background-color: @grey6;
520
520
521 p {
521 p {
522 margin: 0;
522 margin: 0;
523 padding: 1em;
523 padding: 1em;
524 line-height: 1em;
524 line-height: 1em;
525 }
525 }
526
526
527 .server-instance { //server instance
527 .server-instance { //server instance
528 display: none;
528 display: none;
529 }
529 }
530
530
531 .title {
531 .title {
532 float: none;
532 float: none;
533 margin: 0 auto;
533 margin: 0 auto;
534 }
534 }
535 }
535 }
536
536
537 button.close {
537 button.close {
538 padding: 0;
538 padding: 0;
539 cursor: pointer;
539 cursor: pointer;
540 background: transparent;
540 background: transparent;
541 border: 0;
541 border: 0;
542 .box-shadow(none);
542 .box-shadow(none);
543 -webkit-appearance: none;
543 -webkit-appearance: none;
544 }
544 }
545
545
546 .close {
546 .close {
547 float: right;
547 float: right;
548 font-size: 21px;
548 font-size: 21px;
549 font-family: @text-bootstrap;
549 font-family: @text-bootstrap;
550 line-height: 1em;
550 line-height: 1em;
551 font-weight: bold;
551 font-weight: bold;
552 color: @grey2;
552 color: @grey2;
553
553
554 &:hover,
554 &:hover,
555 &:focus {
555 &:focus {
556 color: @grey1;
556 color: @grey1;
557 text-decoration: none;
557 text-decoration: none;
558 cursor: pointer;
558 cursor: pointer;
559 }
559 }
560 }
560 }
561
561
562 // GRID
562 // GRID
563 .sorting,
563 .sorting,
564 .sorting_desc,
564 .sorting_desc,
565 .sorting_asc {
565 .sorting_asc {
566 cursor: pointer;
566 cursor: pointer;
567 }
567 }
568 .sorting_desc:after {
568 .sorting_desc:after {
569 content: "\00A0\25B2";
569 content: "\00A0\25B2";
570 font-size: .75em;
570 font-size: .75em;
571 }
571 }
572 .sorting_asc:after {
572 .sorting_asc:after {
573 content: "\00A0\25BC";
573 content: "\00A0\25BC";
574 font-size: .68em;
574 font-size: .68em;
575 }
575 }
576
576
577
577
578 .user_auth_tokens {
578 .user_auth_tokens {
579
579
580 &.truncate {
580 &.truncate {
581 white-space: nowrap;
581 white-space: nowrap;
582 overflow: hidden;
582 overflow: hidden;
583 text-overflow: ellipsis;
583 text-overflow: ellipsis;
584 }
584 }
585
585
586 .fields .field .input {
586 .fields .field .input {
587 margin: 0;
587 margin: 0;
588 }
588 }
589
589
590 input#description {
590 input#description {
591 width: 100px;
591 width: 100px;
592 margin: 0;
592 margin: 0;
593 }
593 }
594
594
595 .drop-menu {
595 .drop-menu {
596 // TODO: johbo: Remove this, should work out of the box when
596 // TODO: johbo: Remove this, should work out of the box when
597 // having multiple inputs inline
597 // having multiple inputs inline
598 margin: 0 0 0 5px;
598 margin: 0 0 0 5px;
599 }
599 }
600 }
600 }
601 #user_list_table {
601 #user_list_table {
602 .closed {
602 .closed {
603 background-color: @grey6;
603 background-color: @grey6;
604 }
604 }
605 }
605 }
606
606
607
607
608 input {
608 input {
609 &.disabled {
609 &.disabled {
610 opacity: .5;
610 opacity: .5;
611 }
611 }
612 }
612 }
613
613
614 // remove extra padding in firefox
614 // remove extra padding in firefox
615 input::-moz-focus-inner { border:0; padding:0 }
615 input::-moz-focus-inner { border:0; padding:0 }
616
616
617 .adjacent input {
617 .adjacent input {
618 margin-bottom: @padding;
618 margin-bottom: @padding;
619 }
619 }
620
620
621 .permissions_boxes {
621 .permissions_boxes {
622 display: block;
622 display: block;
623 }
623 }
624
624
625 //FORMS
625 //FORMS
626
626
627 .medium-inline,
627 .medium-inline,
628 input#description.medium-inline {
628 input#description.medium-inline {
629 display: inline;
629 display: inline;
630 width: @medium-inline-input-width;
630 width: @medium-inline-input-width;
631 min-width: 100px;
631 min-width: 100px;
632 }
632 }
633
633
634 select {
634 select {
635 //reset
635 //reset
636 -webkit-appearance: none;
636 -webkit-appearance: none;
637 -moz-appearance: none;
637 -moz-appearance: none;
638
638
639 display: inline-block;
639 display: inline-block;
640 height: 28px;
640 height: 28px;
641 width: auto;
641 width: auto;
642 margin: 0 @padding @padding 0;
642 margin: 0 @padding @padding 0;
643 padding: 0 18px 0 8px;
643 padding: 0 18px 0 8px;
644 line-height:1em;
644 line-height:1em;
645 font-size: @basefontsize;
645 font-size: @basefontsize;
646 border: @border-thickness solid @rcblue;
646 border: @border-thickness solid @rcblue;
647 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
647 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
648 color: @rcblue;
648 color: @rcblue;
649
649
650 &:after {
650 &:after {
651 content: "\00A0\25BE";
651 content: "\00A0\25BE";
652 }
652 }
653
653
654 &:focus {
654 &:focus {
655 outline: none;
655 outline: none;
656 }
656 }
657 }
657 }
658
658
659 option {
659 option {
660 &:focus {
660 &:focus {
661 outline: none;
661 outline: none;
662 }
662 }
663 }
663 }
664
664
665 input,
665 input,
666 textarea {
666 textarea {
667 padding: @input-padding;
667 padding: @input-padding;
668 border: @input-border-thickness solid @border-highlight-color;
668 border: @input-border-thickness solid @border-highlight-color;
669 .border-radius (@border-radius);
669 .border-radius (@border-radius);
670 font-family: @text-light;
670 font-family: @text-light;
671 font-size: @basefontsize;
671 font-size: @basefontsize;
672
672
673 &.input-sm {
673 &.input-sm {
674 padding: 5px;
674 padding: 5px;
675 }
675 }
676
676
677 &#description {
677 &#description {
678 min-width: @input-description-minwidth;
678 min-width: @input-description-minwidth;
679 min-height: 1em;
679 min-height: 1em;
680 padding: 10px;
680 padding: 10px;
681 }
681 }
682 }
682 }
683
683
684 .field-sm {
684 .field-sm {
685 input,
685 input,
686 textarea {
686 textarea {
687 padding: 5px;
687 padding: 5px;
688 }
688 }
689 }
689 }
690
690
691 textarea {
691 textarea {
692 display: block;
692 display: block;
693 clear: both;
693 clear: both;
694 width: 100%;
694 width: 100%;
695 min-height: 100px;
695 min-height: 100px;
696 margin-bottom: @padding;
696 margin-bottom: @padding;
697 .box-sizing(border-box);
697 .box-sizing(border-box);
698 overflow: auto;
698 overflow: auto;
699 }
699 }
700
700
701 label {
701 label {
702 font-family: @text-light;
702 font-family: @text-light;
703 }
703 }
704
704
705 // GRAVATARS
705 // GRAVATARS
706 // centers gravatar on username to the right
706 // centers gravatar on username to the right
707
707
708 .gravatar {
708 .gravatar {
709 display: inline;
709 display: inline;
710 min-width: 16px;
710 min-width: 16px;
711 min-height: 16px;
711 min-height: 16px;
712 margin: -5px 0;
712 margin: -5px 0;
713 padding: 0;
713 padding: 0;
714 line-height: 1em;
714 line-height: 1em;
715 border: 1px solid @grey4;
715 border: 1px solid @grey4;
716 box-sizing: content-box;
716 box-sizing: content-box;
717
717
718 &.gravatar-large {
718 &.gravatar-large {
719 margin: -0.5em .25em -0.5em 0;
719 margin: -0.5em .25em -0.5em 0;
720 }
720 }
721
721
722 & + .user {
722 & + .user {
723 display: inline;
723 display: inline;
724 margin: 0;
724 margin: 0;
725 padding: 0 0 0 .17em;
725 padding: 0 0 0 .17em;
726 line-height: 1em;
726 line-height: 1em;
727 }
727 }
728 }
728 }
729
729
730 .user-inline-data {
730 .user-inline-data {
731 display: inline-block;
731 display: inline-block;
732 float: left;
732 float: left;
733 padding-left: .5em;
733 padding-left: .5em;
734 line-height: 1.3em;
734 line-height: 1.3em;
735 }
735 }
736
736
737 .rc-user { // gravatar + user wrapper
737 .rc-user { // gravatar + user wrapper
738 float: left;
738 float: left;
739 position: relative;
739 position: relative;
740 min-width: 100px;
740 min-width: 100px;
741 max-width: 200px;
741 max-width: 200px;
742 min-height: (@gravatar-size + @border-thickness * 2); // account for border
742 min-height: (@gravatar-size + @border-thickness * 2); // account for border
743 display: block;
743 display: block;
744 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
744 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
745
745
746
746
747 .gravatar {
747 .gravatar {
748 display: block;
748 display: block;
749 position: absolute;
749 position: absolute;
750 top: 0;
750 top: 0;
751 left: 0;
751 left: 0;
752 min-width: @gravatar-size;
752 min-width: @gravatar-size;
753 min-height: @gravatar-size;
753 min-height: @gravatar-size;
754 margin: 0;
754 margin: 0;
755 }
755 }
756
756
757 .user {
757 .user {
758 display: block;
758 display: block;
759 max-width: 175px;
759 max-width: 175px;
760 padding-top: 2px;
760 padding-top: 2px;
761 overflow: hidden;
761 overflow: hidden;
762 text-overflow: ellipsis;
762 text-overflow: ellipsis;
763 }
763 }
764 }
764 }
765
765
766 .gist-gravatar,
766 .gist-gravatar,
767 .journal_container {
767 .journal_container {
768 .gravatar-large {
768 .gravatar-large {
769 margin: 0 .5em -10px 0;
769 margin: 0 .5em -10px 0;
770 }
770 }
771 }
771 }
772
772
773
773
774 // ADMIN SETTINGS
774 // ADMIN SETTINGS
775
775
776 // Tag Patterns
776 // Tag Patterns
777 .tag_patterns {
777 .tag_patterns {
778 .tag_input {
778 .tag_input {
779 margin-bottom: @padding;
779 margin-bottom: @padding;
780 }
780 }
781 }
781 }
782
782
783 .locked_input {
783 .locked_input {
784 position: relative;
784 position: relative;
785
785
786 input {
786 input {
787 display: inline;
787 display: inline;
788 margin: 3px 5px 0px 0px;
788 margin: 3px 5px 0px 0px;
789 }
789 }
790
790
791 br {
791 br {
792 display: none;
792 display: none;
793 }
793 }
794
794
795 .error-message {
795 .error-message {
796 float: left;
796 float: left;
797 width: 100%;
797 width: 100%;
798 }
798 }
799
799
800 .lock_input_button {
800 .lock_input_button {
801 display: inline;
801 display: inline;
802 }
802 }
803
803
804 .help-block {
804 .help-block {
805 clear: both;
805 clear: both;
806 }
806 }
807 }
807 }
808
808
809 // Notifications
809 // Notifications
810
810
811 .notifications_buttons {
811 .notifications_buttons {
812 margin: 0 0 @space 0;
812 margin: 0 0 @space 0;
813 padding: 0;
813 padding: 0;
814
814
815 .btn {
815 .btn {
816 display: inline-block;
816 display: inline-block;
817 }
817 }
818 }
818 }
819
819
820 .notification-list {
820 .notification-list {
821
821
822 div {
822 div {
823 display: inline-block;
823 display: inline-block;
824 vertical-align: middle;
824 vertical-align: middle;
825 }
825 }
826
826
827 .container {
827 .container {
828 display: block;
828 display: block;
829 margin: 0 0 @padding 0;
829 margin: 0 0 @padding 0;
830 }
830 }
831
831
832 .delete-notifications {
832 .delete-notifications {
833 margin-left: @padding;
833 margin-left: @padding;
834 text-align: right;
834 text-align: right;
835 cursor: pointer;
835 cursor: pointer;
836 }
836 }
837
837
838 .read-notifications {
838 .read-notifications {
839 margin-left: @padding/2;
839 margin-left: @padding/2;
840 text-align: right;
840 text-align: right;
841 width: 35px;
841 width: 35px;
842 cursor: pointer;
842 cursor: pointer;
843 }
843 }
844
844
845 .icon-minus-sign {
845 .icon-minus-sign {
846 color: @alert2;
846 color: @alert2;
847 }
847 }
848
848
849 .icon-ok-sign {
849 .icon-ok-sign {
850 color: @alert1;
850 color: @alert1;
851 }
851 }
852 }
852 }
853
853
854 .user_settings {
854 .user_settings {
855 float: left;
855 float: left;
856 clear: both;
856 clear: both;
857 display: block;
857 display: block;
858 width: 100%;
858 width: 100%;
859
859
860 .gravatar_box {
860 .gravatar_box {
861 margin-bottom: @padding;
861 margin-bottom: @padding;
862
862
863 &:after {
863 &:after {
864 content: " ";
864 content: " ";
865 clear: both;
865 clear: both;
866 width: 100%;
866 width: 100%;
867 }
867 }
868 }
868 }
869
869
870 .fields .field {
870 .fields .field {
871 clear: both;
871 clear: both;
872 }
872 }
873 }
873 }
874
874
875 .advanced_settings {
875 .advanced_settings {
876 margin-bottom: @space;
876 margin-bottom: @space;
877
877
878 .help-block {
878 .help-block {
879 margin-left: 0;
879 margin-left: 0;
880 }
880 }
881
881
882 button + .help-block {
882 button + .help-block {
883 margin-top: @padding;
883 margin-top: @padding;
884 }
884 }
885 }
885 }
886
886
887 // admin settings radio buttons and labels
887 // admin settings radio buttons and labels
888 .label-2 {
888 .label-2 {
889 float: left;
889 float: left;
890 width: @label2-width;
890 width: @label2-width;
891
891
892 label {
892 label {
893 color: @grey1;
893 color: @grey1;
894 }
894 }
895 }
895 }
896 .checkboxes {
896 .checkboxes {
897 float: left;
897 float: left;
898 width: @checkboxes-width;
898 width: @checkboxes-width;
899 margin-bottom: @padding;
899 margin-bottom: @padding;
900
900
901 .checkbox {
901 .checkbox {
902 width: 100%;
902 width: 100%;
903
903
904 label {
904 label {
905 margin: 0;
905 margin: 0;
906 padding: 0;
906 padding: 0;
907 }
907 }
908 }
908 }
909
909
910 .checkbox + .checkbox {
910 .checkbox + .checkbox {
911 display: inline-block;
911 display: inline-block;
912 }
912 }
913
913
914 label {
914 label {
915 margin-right: 1em;
915 margin-right: 1em;
916 }
916 }
917 }
917 }
918
918
919 // CHANGELOG
919 // CHANGELOG
920 .container_header {
920 .container_header {
921 float: left;
921 float: left;
922 display: block;
922 display: block;
923 width: 100%;
923 width: 100%;
924 margin: @padding 0 @padding;
924 margin: @padding 0 @padding;
925
925
926 #filter_changelog {
926 #filter_changelog {
927 float: left;
927 float: left;
928 margin-right: @padding;
928 margin-right: @padding;
929 }
929 }
930
930
931 .breadcrumbs_light {
931 .breadcrumbs_light {
932 display: inline-block;
932 display: inline-block;
933 }
933 }
934 }
934 }
935
935
936 .info_box {
936 .info_box {
937 float: right;
937 float: right;
938 }
938 }
939
939
940
940
941 #graph_nodes {
941 #graph_nodes {
942 padding-top: 43px;
942 padding-top: 43px;
943 }
943 }
944
944
945 #graph_content{
945 #graph_content{
946
946
947 // adjust for table headers so that graph renders properly
947 // adjust for table headers so that graph renders properly
948 // #graph_nodes padding - table cell padding
948 // #graph_nodes padding - table cell padding
949 padding-top: (@space - (@basefontsize * 2.4));
949 padding-top: (@space - (@basefontsize * 2.4));
950
950
951 &.graph_full_width {
951 &.graph_full_width {
952 width: 100%;
952 width: 100%;
953 max-width: 100%;
953 max-width: 100%;
954 }
954 }
955 }
955 }
956
956
957 #graph {
957 #graph {
958 .flag_status {
958 .flag_status {
959 margin: 0;
959 margin: 0;
960 }
960 }
961
961
962 .pagination-left {
962 .pagination-left {
963 float: left;
963 float: left;
964 clear: both;
964 clear: both;
965 }
965 }
966
966
967 .log-container {
967 .log-container {
968 max-width: 345px;
968 max-width: 345px;
969
969
970 .message{
970 .message{
971 max-width: 340px;
971 max-width: 340px;
972 }
972 }
973 }
973 }
974
974
975 .graph-col-wrapper {
975 .graph-col-wrapper {
976 padding-left: 110px;
976 padding-left: 110px;
977
977
978 #graph_nodes {
978 #graph_nodes {
979 width: 100px;
979 width: 100px;
980 margin-left: -110px;
980 margin-left: -110px;
981 float: left;
981 float: left;
982 clear: left;
982 clear: left;
983 }
983 }
984 }
984 }
985
985
986 .load-more-commits {
986 .load-more-commits {
987 text-align: center;
987 text-align: center;
988 }
988 }
989 .load-more-commits:hover {
989 .load-more-commits:hover {
990 background-color: @grey7;
990 background-color: @grey7;
991 }
991 }
992 .load-more-commits {
992 .load-more-commits {
993 a {
993 a {
994 display: block;
994 display: block;
995 }
995 }
996 }
996 }
997 }
997 }
998
998
999 #filter_changelog {
999 #filter_changelog {
1000 float: left;
1000 float: left;
1001 }
1001 }
1002
1002
1003
1003
1004 //--- THEME ------------------//
1004 //--- THEME ------------------//
1005
1005
1006 #logo {
1006 #logo {
1007 float: left;
1007 float: left;
1008 margin: 9px 0 0 0;
1008 margin: 9px 0 0 0;
1009
1009
1010 .header {
1010 .header {
1011 background-color: transparent;
1011 background-color: transparent;
1012 }
1012 }
1013
1013
1014 a {
1014 a {
1015 display: inline-block;
1015 display: inline-block;
1016 }
1016 }
1017
1017
1018 img {
1018 img {
1019 height:30px;
1019 height:30px;
1020 }
1020 }
1021 }
1021 }
1022
1022
1023 .logo-wrapper {
1023 .logo-wrapper {
1024 float:left;
1024 float:left;
1025 }
1025 }
1026
1026
1027 .branding{
1027 .branding {
1028 float: left;
1028 float: left;
1029 padding: 9px 2px;
1029 padding: 9px 2px;
1030 line-height: 1em;
1030 line-height: 1em;
1031 font-size: @navigation-fontsize;
1031 font-size: @navigation-fontsize;
1032
1033 a {
1034 color: @grey5
1035 }
1032 }
1036 }
1033
1037
1034 img {
1038 img {
1035 border: none;
1039 border: none;
1036 outline: none;
1040 outline: none;
1037 }
1041 }
1038 user-profile-header
1042 user-profile-header
1039 label {
1043 label {
1040
1044
1041 input[type="checkbox"] {
1045 input[type="checkbox"] {
1042 margin-right: 1em;
1046 margin-right: 1em;
1043 }
1047 }
1044 input[type="radio"] {
1048 input[type="radio"] {
1045 margin-right: 1em;
1049 margin-right: 1em;
1046 }
1050 }
1047 }
1051 }
1048
1052
1049 .flag_status {
1053 .flag_status {
1050 margin: 2px 8px 6px 2px;
1054 margin: 2px 8px 6px 2px;
1051 &.under_review {
1055 &.under_review {
1052 .circle(5px, @alert3);
1056 .circle(5px, @alert3);
1053 }
1057 }
1054 &.approved {
1058 &.approved {
1055 .circle(5px, @alert1);
1059 .circle(5px, @alert1);
1056 }
1060 }
1057 &.rejected,
1061 &.rejected,
1058 &.forced_closed{
1062 &.forced_closed{
1059 .circle(5px, @alert2);
1063 .circle(5px, @alert2);
1060 }
1064 }
1061 &.not_reviewed {
1065 &.not_reviewed {
1062 .circle(5px, @grey5);
1066 .circle(5px, @grey5);
1063 }
1067 }
1064 }
1068 }
1065
1069
1066 .flag_status_comment_box {
1070 .flag_status_comment_box {
1067 margin: 5px 6px 0px 2px;
1071 margin: 5px 6px 0px 2px;
1068 }
1072 }
1069 .test_pattern_preview {
1073 .test_pattern_preview {
1070 margin: @space 0;
1074 margin: @space 0;
1071
1075
1072 p {
1076 p {
1073 margin-bottom: 0;
1077 margin-bottom: 0;
1074 border-bottom: @border-thickness solid @border-default-color;
1078 border-bottom: @border-thickness solid @border-default-color;
1075 color: @grey3;
1079 color: @grey3;
1076 }
1080 }
1077
1081
1078 .btn {
1082 .btn {
1079 margin-bottom: @padding;
1083 margin-bottom: @padding;
1080 }
1084 }
1081 }
1085 }
1082 #test_pattern_result {
1086 #test_pattern_result {
1083 display: none;
1087 display: none;
1084 &:extend(pre);
1088 &:extend(pre);
1085 padding: .9em;
1089 padding: .9em;
1086 color: @grey3;
1090 color: @grey3;
1087 background-color: @grey7;
1091 background-color: @grey7;
1088 border-right: @border-thickness solid @border-default-color;
1092 border-right: @border-thickness solid @border-default-color;
1089 border-bottom: @border-thickness solid @border-default-color;
1093 border-bottom: @border-thickness solid @border-default-color;
1090 border-left: @border-thickness solid @border-default-color;
1094 border-left: @border-thickness solid @border-default-color;
1091 }
1095 }
1092
1096
1093 #repo_vcs_settings {
1097 #repo_vcs_settings {
1094 #inherit_overlay_vcs_default {
1098 #inherit_overlay_vcs_default {
1095 display: none;
1099 display: none;
1096 }
1100 }
1097 #inherit_overlay_vcs_custom {
1101 #inherit_overlay_vcs_custom {
1098 display: custom;
1102 display: custom;
1099 }
1103 }
1100 &.inherited {
1104 &.inherited {
1101 #inherit_overlay_vcs_default {
1105 #inherit_overlay_vcs_default {
1102 display: block;
1106 display: block;
1103 }
1107 }
1104 #inherit_overlay_vcs_custom {
1108 #inherit_overlay_vcs_custom {
1105 display: none;
1109 display: none;
1106 }
1110 }
1107 }
1111 }
1108 }
1112 }
1109
1113
1110 .issue-tracker-link {
1114 .issue-tracker-link {
1111 color: @rcblue;
1115 color: @rcblue;
1112 }
1116 }
1113
1117
1114 // Issue Tracker Table Show/Hide
1118 // Issue Tracker Table Show/Hide
1115 #repo_issue_tracker {
1119 #repo_issue_tracker {
1116 #inherit_overlay {
1120 #inherit_overlay {
1117 display: none;
1121 display: none;
1118 }
1122 }
1119 #custom_overlay {
1123 #custom_overlay {
1120 display: custom;
1124 display: custom;
1121 }
1125 }
1122 &.inherited {
1126 &.inherited {
1123 #inherit_overlay {
1127 #inherit_overlay {
1124 display: block;
1128 display: block;
1125 }
1129 }
1126 #custom_overlay {
1130 #custom_overlay {
1127 display: none;
1131 display: none;
1128 }
1132 }
1129 }
1133 }
1130 }
1134 }
1131 table.issuetracker {
1135 table.issuetracker {
1132 &.readonly {
1136 &.readonly {
1133 tr, td {
1137 tr, td {
1134 color: @grey3;
1138 color: @grey3;
1135 }
1139 }
1136 }
1140 }
1137 .edit {
1141 .edit {
1138 display: none;
1142 display: none;
1139 }
1143 }
1140 .editopen {
1144 .editopen {
1141 .edit {
1145 .edit {
1142 display: inline;
1146 display: inline;
1143 }
1147 }
1144 .entry {
1148 .entry {
1145 display: none;
1149 display: none;
1146 }
1150 }
1147 }
1151 }
1148 tr td.td-action {
1152 tr td.td-action {
1149 min-width: 117px;
1153 min-width: 117px;
1150 }
1154 }
1151 td input {
1155 td input {
1152 max-width: none;
1156 max-width: none;
1153 min-width: 30px;
1157 min-width: 30px;
1154 width: 80%;
1158 width: 80%;
1155 }
1159 }
1156 .issuetracker_pref input {
1160 .issuetracker_pref input {
1157 width: 40%;
1161 width: 40%;
1158 }
1162 }
1159 input.edit_issuetracker_update {
1163 input.edit_issuetracker_update {
1160 margin-right: 0;
1164 margin-right: 0;
1161 width: auto;
1165 width: auto;
1162 }
1166 }
1163 }
1167 }
1164
1168
1165 table.integrations {
1169 table.integrations {
1166 .td-icon {
1170 .td-icon {
1167 width: 20px;
1171 width: 20px;
1168 .integration-icon {
1172 .integration-icon {
1169 height: 20px;
1173 height: 20px;
1170 width: 20px;
1174 width: 20px;
1171 }
1175 }
1172 }
1176 }
1173 }
1177 }
1174
1178
1175 .integrations {
1179 .integrations {
1176 a.integration-box {
1180 a.integration-box {
1177 color: @text-color;
1181 color: @text-color;
1178 &:hover {
1182 &:hover {
1179 .panel {
1183 .panel {
1180 background: #fbfbfb;
1184 background: #fbfbfb;
1181 }
1185 }
1182 }
1186 }
1183 .integration-icon {
1187 .integration-icon {
1184 width: 30px;
1188 width: 30px;
1185 height: 30px;
1189 height: 30px;
1186 margin-right: 20px;
1190 margin-right: 20px;
1187 float: left;
1191 float: left;
1188 }
1192 }
1189
1193
1190 .panel-body {
1194 .panel-body {
1191 padding: 10px;
1195 padding: 10px;
1192 }
1196 }
1193 .panel {
1197 .panel {
1194 margin-bottom: 10px;
1198 margin-bottom: 10px;
1195 }
1199 }
1196 h2 {
1200 h2 {
1197 display: inline-block;
1201 display: inline-block;
1198 margin: 0;
1202 margin: 0;
1199 min-width: 140px;
1203 min-width: 140px;
1200 }
1204 }
1201 }
1205 }
1202 a.integration-box.dummy-integration {
1206 a.integration-box.dummy-integration {
1203 color: @grey4
1207 color: @grey4
1204 }
1208 }
1205 }
1209 }
1206
1210
1207 //Permissions Settings
1211 //Permissions Settings
1208 #add_perm {
1212 #add_perm {
1209 margin: 0 0 @padding;
1213 margin: 0 0 @padding;
1210 cursor: pointer;
1214 cursor: pointer;
1211 }
1215 }
1212
1216
1213 .perm_ac {
1217 .perm_ac {
1214 input {
1218 input {
1215 width: 95%;
1219 width: 95%;
1216 }
1220 }
1217 }
1221 }
1218
1222
1219 .autocomplete-suggestions {
1223 .autocomplete-suggestions {
1220 width: auto !important; // overrides autocomplete.js
1224 width: auto !important; // overrides autocomplete.js
1221 margin: 0;
1225 margin: 0;
1222 border: @border-thickness solid @rcblue;
1226 border: @border-thickness solid @rcblue;
1223 border-radius: @border-radius;
1227 border-radius: @border-radius;
1224 color: @rcblue;
1228 color: @rcblue;
1225 background-color: white;
1229 background-color: white;
1226 }
1230 }
1227 .autocomplete-selected {
1231 .autocomplete-selected {
1228 background: #F0F0F0;
1232 background: #F0F0F0;
1229 }
1233 }
1230 .ac-container-wrap {
1234 .ac-container-wrap {
1231 margin: 0;
1235 margin: 0;
1232 padding: 8px;
1236 padding: 8px;
1233 border-bottom: @border-thickness solid @rclightblue;
1237 border-bottom: @border-thickness solid @rclightblue;
1234 list-style-type: none;
1238 list-style-type: none;
1235 cursor: pointer;
1239 cursor: pointer;
1236
1240
1237 &:hover {
1241 &:hover {
1238 background-color: @rclightblue;
1242 background-color: @rclightblue;
1239 }
1243 }
1240
1244
1241 img {
1245 img {
1242 height: @gravatar-size;
1246 height: @gravatar-size;
1243 width: @gravatar-size;
1247 width: @gravatar-size;
1244 margin-right: 1em;
1248 margin-right: 1em;
1245 }
1249 }
1246
1250
1247 strong {
1251 strong {
1248 font-weight: normal;
1252 font-weight: normal;
1249 }
1253 }
1250 }
1254 }
1251
1255
1252 // Settings Dropdown
1256 // Settings Dropdown
1253 .user-menu .container {
1257 .user-menu .container {
1254 padding: 0 4px;
1258 padding: 0 4px;
1255 margin: 0;
1259 margin: 0;
1256 }
1260 }
1257
1261
1258 .user-menu .gravatar {
1262 .user-menu .gravatar {
1259 cursor: pointer;
1263 cursor: pointer;
1260 }
1264 }
1261
1265
1262 .codeblock {
1266 .codeblock {
1263 margin-bottom: @padding;
1267 margin-bottom: @padding;
1264 clear: both;
1268 clear: both;
1265
1269
1266 .stats {
1270 .stats {
1267 overflow: hidden;
1271 overflow: hidden;
1268 }
1272 }
1269
1273
1270 .message{
1274 .message{
1271 textarea{
1275 textarea{
1272 margin: 0;
1276 margin: 0;
1273 }
1277 }
1274 }
1278 }
1275
1279
1276 .code-header {
1280 .code-header {
1277 .stats {
1281 .stats {
1278 line-height: 2em;
1282 line-height: 2em;
1279
1283
1280 .revision_id {
1284 .revision_id {
1281 margin-left: 0;
1285 margin-left: 0;
1282 }
1286 }
1283 .buttons {
1287 .buttons {
1284 padding-right: 0;
1288 padding-right: 0;
1285 }
1289 }
1286 }
1290 }
1287
1291
1288 .item{
1292 .item{
1289 margin-right: 0.5em;
1293 margin-right: 0.5em;
1290 }
1294 }
1291 }
1295 }
1292
1296
1293 #editor_container{
1297 #editor_container{
1294 position: relative;
1298 position: relative;
1295 margin: @padding;
1299 margin: @padding;
1296 }
1300 }
1297 }
1301 }
1298
1302
1299 #file_history_container {
1303 #file_history_container {
1300 display: none;
1304 display: none;
1301 }
1305 }
1302
1306
1303 .file-history-inner {
1307 .file-history-inner {
1304 margin-bottom: 10px;
1308 margin-bottom: 10px;
1305 }
1309 }
1306
1310
1307 // Pull Requests
1311 // Pull Requests
1308 .summary-details {
1312 .summary-details {
1309 width: 72%;
1313 width: 72%;
1310 }
1314 }
1311 .pr-summary {
1315 .pr-summary {
1312 border-bottom: @border-thickness solid @grey5;
1316 border-bottom: @border-thickness solid @grey5;
1313 margin-bottom: @space;
1317 margin-bottom: @space;
1314 }
1318 }
1315 .reviewers-title {
1319 .reviewers-title {
1316 width: 25%;
1320 width: 25%;
1317 min-width: 200px;
1321 min-width: 200px;
1318 }
1322 }
1319 .reviewers {
1323 .reviewers {
1320 width: 25%;
1324 width: 25%;
1321 min-width: 200px;
1325 min-width: 200px;
1322 }
1326 }
1323 .reviewers ul li {
1327 .reviewers ul li {
1324 position: relative;
1328 position: relative;
1325 width: 100%;
1329 width: 100%;
1326 padding-bottom: 8px;
1330 padding-bottom: 8px;
1327 list-style-type: none;
1331 list-style-type: none;
1328 }
1332 }
1329
1333
1330 .reviewer_entry {
1334 .reviewer_entry {
1331 min-height: 55px;
1335 min-height: 55px;
1332 }
1336 }
1333
1337
1334 .reviewers_member {
1338 .reviewers_member {
1335 width: 100%;
1339 width: 100%;
1336 overflow: auto;
1340 overflow: auto;
1337 }
1341 }
1338 .reviewer_reason {
1342 .reviewer_reason {
1339 padding-left: 20px;
1343 padding-left: 20px;
1340 line-height: 1.5em;
1344 line-height: 1.5em;
1341 }
1345 }
1342 .reviewer_status {
1346 .reviewer_status {
1343 display: inline-block;
1347 display: inline-block;
1344 vertical-align: top;
1348 vertical-align: top;
1345 width: 25px;
1349 width: 25px;
1346 min-width: 25px;
1350 min-width: 25px;
1347 height: 1.2em;
1351 height: 1.2em;
1348 margin-top: 3px;
1352 margin-top: 3px;
1349 line-height: 1em;
1353 line-height: 1em;
1350 }
1354 }
1351
1355
1352 .reviewer_name {
1356 .reviewer_name {
1353 display: inline-block;
1357 display: inline-block;
1354 max-width: 83%;
1358 max-width: 83%;
1355 padding-right: 20px;
1359 padding-right: 20px;
1356 vertical-align: middle;
1360 vertical-align: middle;
1357 line-height: 1;
1361 line-height: 1;
1358
1362
1359 .rc-user {
1363 .rc-user {
1360 min-width: 0;
1364 min-width: 0;
1361 margin: -2px 1em 0 0;
1365 margin: -2px 1em 0 0;
1362 }
1366 }
1363
1367
1364 .reviewer {
1368 .reviewer {
1365 float: left;
1369 float: left;
1366 }
1370 }
1367 }
1371 }
1368
1372
1369 .reviewer_member_mandatory {
1373 .reviewer_member_mandatory {
1370 position: absolute;
1374 position: absolute;
1371 left: 15px;
1375 left: 15px;
1372 top: 8px;
1376 top: 8px;
1373 width: 16px;
1377 width: 16px;
1374 font-size: 11px;
1378 font-size: 11px;
1375 margin: 0;
1379 margin: 0;
1376 padding: 0;
1380 padding: 0;
1377 color: black;
1381 color: black;
1378 }
1382 }
1379
1383
1380 .reviewer_member_mandatory_remove,
1384 .reviewer_member_mandatory_remove,
1381 .reviewer_member_remove {
1385 .reviewer_member_remove {
1382 position: absolute;
1386 position: absolute;
1383 right: 0;
1387 right: 0;
1384 top: 0;
1388 top: 0;
1385 width: 16px;
1389 width: 16px;
1386 margin-bottom: 10px;
1390 margin-bottom: 10px;
1387 padding: 0;
1391 padding: 0;
1388 color: black;
1392 color: black;
1389 }
1393 }
1390
1394
1391 .reviewer_member_mandatory_remove {
1395 .reviewer_member_mandatory_remove {
1392 color: @grey4;
1396 color: @grey4;
1393 }
1397 }
1394
1398
1395 .reviewer_member_status {
1399 .reviewer_member_status {
1396 margin-top: 5px;
1400 margin-top: 5px;
1397 }
1401 }
1398 .pr-summary #summary{
1402 .pr-summary #summary{
1399 width: 100%;
1403 width: 100%;
1400 }
1404 }
1401 .pr-summary .action_button:hover {
1405 .pr-summary .action_button:hover {
1402 border: 0;
1406 border: 0;
1403 cursor: pointer;
1407 cursor: pointer;
1404 }
1408 }
1405 .pr-details-title {
1409 .pr-details-title {
1406 padding-bottom: 8px;
1410 padding-bottom: 8px;
1407 border-bottom: @border-thickness solid @grey5;
1411 border-bottom: @border-thickness solid @grey5;
1408
1412
1409 .action_button.disabled {
1413 .action_button.disabled {
1410 color: @grey4;
1414 color: @grey4;
1411 cursor: inherit;
1415 cursor: inherit;
1412 }
1416 }
1413 .action_button {
1417 .action_button {
1414 color: @rcblue;
1418 color: @rcblue;
1415 }
1419 }
1416 }
1420 }
1417 .pr-details-content {
1421 .pr-details-content {
1418 margin-top: @textmargin;
1422 margin-top: @textmargin;
1419 margin-bottom: @textmargin;
1423 margin-bottom: @textmargin;
1420 }
1424 }
1421
1425
1422 .pr-reviewer-rules {
1426 .pr-reviewer-rules {
1423 padding: 10px 0px 20px 0px;
1427 padding: 10px 0px 20px 0px;
1424 }
1428 }
1425
1429
1426 .group_members {
1430 .group_members {
1427 margin-top: 0;
1431 margin-top: 0;
1428 padding: 0;
1432 padding: 0;
1429 list-style: outside none none;
1433 list-style: outside none none;
1430
1434
1431 img {
1435 img {
1432 height: @gravatar-size;
1436 height: @gravatar-size;
1433 width: @gravatar-size;
1437 width: @gravatar-size;
1434 margin-right: .5em;
1438 margin-right: .5em;
1435 margin-left: 3px;
1439 margin-left: 3px;
1436 }
1440 }
1437
1441
1438 .to-delete {
1442 .to-delete {
1439 .user {
1443 .user {
1440 text-decoration: line-through;
1444 text-decoration: line-through;
1441 }
1445 }
1442 }
1446 }
1443 }
1447 }
1444
1448
1445 .compare_view_commits_title {
1449 .compare_view_commits_title {
1446 .disabled {
1450 .disabled {
1447 cursor: inherit;
1451 cursor: inherit;
1448 &:hover{
1452 &:hover{
1449 background-color: inherit;
1453 background-color: inherit;
1450 color: inherit;
1454 color: inherit;
1451 }
1455 }
1452 }
1456 }
1453 }
1457 }
1454
1458
1455 .subtitle-compare {
1459 .subtitle-compare {
1456 margin: -15px 0px 0px 0px;
1460 margin: -15px 0px 0px 0px;
1457 }
1461 }
1458
1462
1459 .comments-summary-td {
1463 .comments-summary-td {
1460 border-top: 1px dashed @grey5;
1464 border-top: 1px dashed @grey5;
1461 }
1465 }
1462
1466
1463 // new entry in group_members
1467 // new entry in group_members
1464 .td-author-new-entry {
1468 .td-author-new-entry {
1465 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1469 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1466 }
1470 }
1467
1471
1468 .usergroup_member_remove {
1472 .usergroup_member_remove {
1469 width: 16px;
1473 width: 16px;
1470 margin-bottom: 10px;
1474 margin-bottom: 10px;
1471 padding: 0;
1475 padding: 0;
1472 color: black !important;
1476 color: black !important;
1473 cursor: pointer;
1477 cursor: pointer;
1474 }
1478 }
1475
1479
1476 .reviewer_ac .ac-input {
1480 .reviewer_ac .ac-input {
1477 width: 92%;
1481 width: 92%;
1478 margin-bottom: 1em;
1482 margin-bottom: 1em;
1479 }
1483 }
1480
1484
1481 .compare_view_commits tr{
1485 .compare_view_commits tr{
1482 height: 20px;
1486 height: 20px;
1483 }
1487 }
1484 .compare_view_commits td {
1488 .compare_view_commits td {
1485 vertical-align: top;
1489 vertical-align: top;
1486 padding-top: 10px;
1490 padding-top: 10px;
1487 }
1491 }
1488 .compare_view_commits .author {
1492 .compare_view_commits .author {
1489 margin-left: 5px;
1493 margin-left: 5px;
1490 }
1494 }
1491
1495
1492 .compare_view_commits {
1496 .compare_view_commits {
1493 .color-a {
1497 .color-a {
1494 color: @alert1;
1498 color: @alert1;
1495 }
1499 }
1496
1500
1497 .color-c {
1501 .color-c {
1498 color: @color3;
1502 color: @color3;
1499 }
1503 }
1500
1504
1501 .color-r {
1505 .color-r {
1502 color: @color5;
1506 color: @color5;
1503 }
1507 }
1504
1508
1505 .color-a-bg {
1509 .color-a-bg {
1506 background-color: @alert1;
1510 background-color: @alert1;
1507 }
1511 }
1508
1512
1509 .color-c-bg {
1513 .color-c-bg {
1510 background-color: @alert3;
1514 background-color: @alert3;
1511 }
1515 }
1512
1516
1513 .color-r-bg {
1517 .color-r-bg {
1514 background-color: @alert2;
1518 background-color: @alert2;
1515 }
1519 }
1516
1520
1517 .color-a-border {
1521 .color-a-border {
1518 border: 1px solid @alert1;
1522 border: 1px solid @alert1;
1519 }
1523 }
1520
1524
1521 .color-c-border {
1525 .color-c-border {
1522 border: 1px solid @alert3;
1526 border: 1px solid @alert3;
1523 }
1527 }
1524
1528
1525 .color-r-border {
1529 .color-r-border {
1526 border: 1px solid @alert2;
1530 border: 1px solid @alert2;
1527 }
1531 }
1528
1532
1529 .commit-change-indicator {
1533 .commit-change-indicator {
1530 width: 15px;
1534 width: 15px;
1531 height: 15px;
1535 height: 15px;
1532 position: relative;
1536 position: relative;
1533 left: 15px;
1537 left: 15px;
1534 }
1538 }
1535
1539
1536 .commit-change-content {
1540 .commit-change-content {
1537 text-align: center;
1541 text-align: center;
1538 vertical-align: middle;
1542 vertical-align: middle;
1539 line-height: 15px;
1543 line-height: 15px;
1540 }
1544 }
1541 }
1545 }
1542
1546
1543 .compare_view_filepath {
1547 .compare_view_filepath {
1544 color: @grey1;
1548 color: @grey1;
1545 }
1549 }
1546
1550
1547 .show_more {
1551 .show_more {
1548 display: inline-block;
1552 display: inline-block;
1549 width: 0;
1553 width: 0;
1550 height: 0;
1554 height: 0;
1551 vertical-align: middle;
1555 vertical-align: middle;
1552 content: "";
1556 content: "";
1553 border: 4px solid;
1557 border: 4px solid;
1554 border-right-color: transparent;
1558 border-right-color: transparent;
1555 border-bottom-color: transparent;
1559 border-bottom-color: transparent;
1556 border-left-color: transparent;
1560 border-left-color: transparent;
1557 font-size: 0;
1561 font-size: 0;
1558 }
1562 }
1559
1563
1560 .journal_more .show_more {
1564 .journal_more .show_more {
1561 display: inline;
1565 display: inline;
1562
1566
1563 &:after {
1567 &:after {
1564 content: none;
1568 content: none;
1565 }
1569 }
1566 }
1570 }
1567
1571
1568 .compare_view_commits .collapse_commit:after {
1572 .compare_view_commits .collapse_commit:after {
1569 cursor: pointer;
1573 cursor: pointer;
1570 content: "\00A0\25B4";
1574 content: "\00A0\25B4";
1571 margin-left: -3px;
1575 margin-left: -3px;
1572 font-size: 17px;
1576 font-size: 17px;
1573 color: @grey4;
1577 color: @grey4;
1574 }
1578 }
1575
1579
1576 .diff_links {
1580 .diff_links {
1577 margin-left: 8px;
1581 margin-left: 8px;
1578 }
1582 }
1579
1583
1580 div.ancestor {
1584 div.ancestor {
1581 margin: -30px 0px;
1585 margin: -30px 0px;
1582 }
1586 }
1583
1587
1584 .cs_icon_td input[type="checkbox"] {
1588 .cs_icon_td input[type="checkbox"] {
1585 display: none;
1589 display: none;
1586 }
1590 }
1587
1591
1588 .cs_icon_td .expand_file_icon:after {
1592 .cs_icon_td .expand_file_icon:after {
1589 cursor: pointer;
1593 cursor: pointer;
1590 content: "\00A0\25B6";
1594 content: "\00A0\25B6";
1591 font-size: 12px;
1595 font-size: 12px;
1592 color: @grey4;
1596 color: @grey4;
1593 }
1597 }
1594
1598
1595 .cs_icon_td .collapse_file_icon:after {
1599 .cs_icon_td .collapse_file_icon:after {
1596 cursor: pointer;
1600 cursor: pointer;
1597 content: "\00A0\25BC";
1601 content: "\00A0\25BC";
1598 font-size: 12px;
1602 font-size: 12px;
1599 color: @grey4;
1603 color: @grey4;
1600 }
1604 }
1601
1605
1602 /*new binary
1606 /*new binary
1603 NEW_FILENODE = 1
1607 NEW_FILENODE = 1
1604 DEL_FILENODE = 2
1608 DEL_FILENODE = 2
1605 MOD_FILENODE = 3
1609 MOD_FILENODE = 3
1606 RENAMED_FILENODE = 4
1610 RENAMED_FILENODE = 4
1607 COPIED_FILENODE = 5
1611 COPIED_FILENODE = 5
1608 CHMOD_FILENODE = 6
1612 CHMOD_FILENODE = 6
1609 BIN_FILENODE = 7
1613 BIN_FILENODE = 7
1610 */
1614 */
1611 .cs_files_expand {
1615 .cs_files_expand {
1612 font-size: @basefontsize + 5px;
1616 font-size: @basefontsize + 5px;
1613 line-height: 1.8em;
1617 line-height: 1.8em;
1614 float: right;
1618 float: right;
1615 }
1619 }
1616
1620
1617 .cs_files_expand span{
1621 .cs_files_expand span{
1618 color: @rcblue;
1622 color: @rcblue;
1619 cursor: pointer;
1623 cursor: pointer;
1620 }
1624 }
1621 .cs_files {
1625 .cs_files {
1622 clear: both;
1626 clear: both;
1623 padding-bottom: @padding;
1627 padding-bottom: @padding;
1624
1628
1625 .cur_cs {
1629 .cur_cs {
1626 margin: 10px 2px;
1630 margin: 10px 2px;
1627 font-weight: bold;
1631 font-weight: bold;
1628 }
1632 }
1629
1633
1630 .node {
1634 .node {
1631 float: left;
1635 float: left;
1632 }
1636 }
1633
1637
1634 .changes {
1638 .changes {
1635 float: right;
1639 float: right;
1636 color: white;
1640 color: white;
1637 font-size: @basefontsize - 4px;
1641 font-size: @basefontsize - 4px;
1638 margin-top: 4px;
1642 margin-top: 4px;
1639 opacity: 0.6;
1643 opacity: 0.6;
1640 filter: Alpha(opacity=60); /* IE8 and earlier */
1644 filter: Alpha(opacity=60); /* IE8 and earlier */
1641
1645
1642 .added {
1646 .added {
1643 background-color: @alert1;
1647 background-color: @alert1;
1644 float: left;
1648 float: left;
1645 text-align: center;
1649 text-align: center;
1646 }
1650 }
1647
1651
1648 .deleted {
1652 .deleted {
1649 background-color: @alert2;
1653 background-color: @alert2;
1650 float: left;
1654 float: left;
1651 text-align: center;
1655 text-align: center;
1652 }
1656 }
1653
1657
1654 .bin {
1658 .bin {
1655 background-color: @alert1;
1659 background-color: @alert1;
1656 text-align: center;
1660 text-align: center;
1657 }
1661 }
1658
1662
1659 /*new binary*/
1663 /*new binary*/
1660 .bin.bin1 {
1664 .bin.bin1 {
1661 background-color: @alert1;
1665 background-color: @alert1;
1662 text-align: center;
1666 text-align: center;
1663 }
1667 }
1664
1668
1665 /*deleted binary*/
1669 /*deleted binary*/
1666 .bin.bin2 {
1670 .bin.bin2 {
1667 background-color: @alert2;
1671 background-color: @alert2;
1668 text-align: center;
1672 text-align: center;
1669 }
1673 }
1670
1674
1671 /*mod binary*/
1675 /*mod binary*/
1672 .bin.bin3 {
1676 .bin.bin3 {
1673 background-color: @grey2;
1677 background-color: @grey2;
1674 text-align: center;
1678 text-align: center;
1675 }
1679 }
1676
1680
1677 /*rename file*/
1681 /*rename file*/
1678 .bin.bin4 {
1682 .bin.bin4 {
1679 background-color: @alert4;
1683 background-color: @alert4;
1680 text-align: center;
1684 text-align: center;
1681 }
1685 }
1682
1686
1683 /*copied file*/
1687 /*copied file*/
1684 .bin.bin5 {
1688 .bin.bin5 {
1685 background-color: @alert4;
1689 background-color: @alert4;
1686 text-align: center;
1690 text-align: center;
1687 }
1691 }
1688
1692
1689 /*chmod file*/
1693 /*chmod file*/
1690 .bin.bin6 {
1694 .bin.bin6 {
1691 background-color: @grey2;
1695 background-color: @grey2;
1692 text-align: center;
1696 text-align: center;
1693 }
1697 }
1694 }
1698 }
1695 }
1699 }
1696
1700
1697 .cs_files .cs_added, .cs_files .cs_A,
1701 .cs_files .cs_added, .cs_files .cs_A,
1698 .cs_files .cs_added, .cs_files .cs_M,
1702 .cs_files .cs_added, .cs_files .cs_M,
1699 .cs_files .cs_added, .cs_files .cs_D {
1703 .cs_files .cs_added, .cs_files .cs_D {
1700 height: 16px;
1704 height: 16px;
1701 padding-right: 10px;
1705 padding-right: 10px;
1702 margin-top: 7px;
1706 margin-top: 7px;
1703 text-align: left;
1707 text-align: left;
1704 }
1708 }
1705
1709
1706 .cs_icon_td {
1710 .cs_icon_td {
1707 min-width: 16px;
1711 min-width: 16px;
1708 width: 16px;
1712 width: 16px;
1709 }
1713 }
1710
1714
1711 .pull-request-merge {
1715 .pull-request-merge {
1712 border: 1px solid @grey5;
1716 border: 1px solid @grey5;
1713 padding: 10px 0px 20px;
1717 padding: 10px 0px 20px;
1714 margin-top: 10px;
1718 margin-top: 10px;
1715 margin-bottom: 20px;
1719 margin-bottom: 20px;
1716 }
1720 }
1717
1721
1718 .pull-request-merge ul {
1722 .pull-request-merge ul {
1719 padding: 0px 0px;
1723 padding: 0px 0px;
1720 }
1724 }
1721
1725
1722 .pull-request-merge li {
1726 .pull-request-merge li {
1723 list-style-type: none;
1727 list-style-type: none;
1724 }
1728 }
1725
1729
1726 .pull-request-merge .pull-request-wrap {
1730 .pull-request-merge .pull-request-wrap {
1727 height: auto;
1731 height: auto;
1728 padding: 0px 0px;
1732 padding: 0px 0px;
1729 text-align: right;
1733 text-align: right;
1730 }
1734 }
1731
1735
1732 .pull-request-merge span {
1736 .pull-request-merge span {
1733 margin-right: 5px;
1737 margin-right: 5px;
1734 }
1738 }
1735
1739
1736 .pull-request-merge-actions {
1740 .pull-request-merge-actions {
1737 min-height: 30px;
1741 min-height: 30px;
1738 padding: 0px 0px;
1742 padding: 0px 0px;
1739 }
1743 }
1740
1744
1741 .pull-request-merge-info {
1745 .pull-request-merge-info {
1742 padding: 0px 5px 5px 0px;
1746 padding: 0px 5px 5px 0px;
1743 }
1747 }
1744
1748
1745 .merge-status {
1749 .merge-status {
1746 margin-right: 5px;
1750 margin-right: 5px;
1747 }
1751 }
1748
1752
1749 .merge-message {
1753 .merge-message {
1750 font-size: 1.2em
1754 font-size: 1.2em
1751 }
1755 }
1752
1756
1753 .merge-message.success i,
1757 .merge-message.success i,
1754 .merge-icon.success i {
1758 .merge-icon.success i {
1755 color:@alert1;
1759 color:@alert1;
1756 }
1760 }
1757
1761
1758 .merge-message.warning i,
1762 .merge-message.warning i,
1759 .merge-icon.warning i {
1763 .merge-icon.warning i {
1760 color: @alert3;
1764 color: @alert3;
1761 }
1765 }
1762
1766
1763 .merge-message.error i,
1767 .merge-message.error i,
1764 .merge-icon.error i {
1768 .merge-icon.error i {
1765 color:@alert2;
1769 color:@alert2;
1766 }
1770 }
1767
1771
1768 .pr-versions {
1772 .pr-versions {
1769 font-size: 1.1em;
1773 font-size: 1.1em;
1770
1774
1771 table {
1775 table {
1772 padding: 0px 5px;
1776 padding: 0px 5px;
1773 }
1777 }
1774
1778
1775 td {
1779 td {
1776 line-height: 15px;
1780 line-height: 15px;
1777 }
1781 }
1778
1782
1779 .flag_status {
1783 .flag_status {
1780 margin: 0;
1784 margin: 0;
1781 }
1785 }
1782
1786
1783 .compare-radio-button {
1787 .compare-radio-button {
1784 position: relative;
1788 position: relative;
1785 top: -3px;
1789 top: -3px;
1786 }
1790 }
1787 }
1791 }
1788
1792
1789
1793
1790 #close_pull_request {
1794 #close_pull_request {
1791 margin-right: 0px;
1795 margin-right: 0px;
1792 }
1796 }
1793
1797
1794 .empty_data {
1798 .empty_data {
1795 color: @grey4;
1799 color: @grey4;
1796 }
1800 }
1797
1801
1798 #changeset_compare_view_content {
1802 #changeset_compare_view_content {
1799 margin-bottom: @space;
1803 margin-bottom: @space;
1800 clear: both;
1804 clear: both;
1801 width: 100%;
1805 width: 100%;
1802 box-sizing: border-box;
1806 box-sizing: border-box;
1803 .border-radius(@border-radius);
1807 .border-radius(@border-radius);
1804
1808
1805 .help-block {
1809 .help-block {
1806 margin: @padding 0;
1810 margin: @padding 0;
1807 color: @text-color;
1811 color: @text-color;
1808 &.pre-formatting {
1812 &.pre-formatting {
1809 white-space: pre;
1813 white-space: pre;
1810 }
1814 }
1811 }
1815 }
1812
1816
1813 .empty_data {
1817 .empty_data {
1814 margin: @padding 0;
1818 margin: @padding 0;
1815 }
1819 }
1816
1820
1817 .alert {
1821 .alert {
1818 margin-bottom: @space;
1822 margin-bottom: @space;
1819 }
1823 }
1820 }
1824 }
1821
1825
1822 .table_disp {
1826 .table_disp {
1823 .status {
1827 .status {
1824 width: auto;
1828 width: auto;
1825
1829
1826 .flag_status {
1830 .flag_status {
1827 float: left;
1831 float: left;
1828 }
1832 }
1829 }
1833 }
1830 }
1834 }
1831
1835
1832
1836
1833 .creation_in_progress {
1837 .creation_in_progress {
1834 color: @grey4
1838 color: @grey4
1835 }
1839 }
1836
1840
1837 .status_box_menu {
1841 .status_box_menu {
1838 margin: 0;
1842 margin: 0;
1839 }
1843 }
1840
1844
1841 .notification-table{
1845 .notification-table{
1842 margin-bottom: @space;
1846 margin-bottom: @space;
1843 display: table;
1847 display: table;
1844 width: 100%;
1848 width: 100%;
1845
1849
1846 .container{
1850 .container{
1847 display: table-row;
1851 display: table-row;
1848
1852
1849 .notification-header{
1853 .notification-header{
1850 border-bottom: @border-thickness solid @border-default-color;
1854 border-bottom: @border-thickness solid @border-default-color;
1851 }
1855 }
1852
1856
1853 .notification-subject{
1857 .notification-subject{
1854 display: table-cell;
1858 display: table-cell;
1855 }
1859 }
1856 }
1860 }
1857 }
1861 }
1858
1862
1859 // Notifications
1863 // Notifications
1860 .notification-header{
1864 .notification-header{
1861 display: table;
1865 display: table;
1862 width: 100%;
1866 width: 100%;
1863 padding: floor(@basefontsize/2) 0;
1867 padding: floor(@basefontsize/2) 0;
1864 line-height: 1em;
1868 line-height: 1em;
1865
1869
1866 .desc, .delete-notifications, .read-notifications{
1870 .desc, .delete-notifications, .read-notifications{
1867 display: table-cell;
1871 display: table-cell;
1868 text-align: left;
1872 text-align: left;
1869 }
1873 }
1870
1874
1871 .desc{
1875 .desc{
1872 width: 1163px;
1876 width: 1163px;
1873 }
1877 }
1874
1878
1875 .delete-notifications, .read-notifications{
1879 .delete-notifications, .read-notifications{
1876 width: 35px;
1880 width: 35px;
1877 min-width: 35px; //fixes when only one button is displayed
1881 min-width: 35px; //fixes when only one button is displayed
1878 }
1882 }
1879 }
1883 }
1880
1884
1881 .notification-body {
1885 .notification-body {
1882 .markdown-block,
1886 .markdown-block,
1883 .rst-block {
1887 .rst-block {
1884 padding: @padding 0;
1888 padding: @padding 0;
1885 }
1889 }
1886
1890
1887 .notification-subject {
1891 .notification-subject {
1888 padding: @textmargin 0;
1892 padding: @textmargin 0;
1889 border-bottom: @border-thickness solid @border-default-color;
1893 border-bottom: @border-thickness solid @border-default-color;
1890 }
1894 }
1891 }
1895 }
1892
1896
1893
1897
1894 .notifications_buttons{
1898 .notifications_buttons{
1895 float: right;
1899 float: right;
1896 }
1900 }
1897
1901
1898 #notification-status{
1902 #notification-status{
1899 display: inline;
1903 display: inline;
1900 }
1904 }
1901
1905
1902 // Repositories
1906 // Repositories
1903
1907
1904 #summary.fields{
1908 #summary.fields{
1905 display: table;
1909 display: table;
1906
1910
1907 .field{
1911 .field{
1908 display: table-row;
1912 display: table-row;
1909
1913
1910 .label-summary{
1914 .label-summary{
1911 display: table-cell;
1915 display: table-cell;
1912 min-width: @label-summary-minwidth;
1916 min-width: @label-summary-minwidth;
1913 padding-top: @padding/2;
1917 padding-top: @padding/2;
1914 padding-bottom: @padding/2;
1918 padding-bottom: @padding/2;
1915 padding-right: @padding/2;
1919 padding-right: @padding/2;
1916 }
1920 }
1917
1921
1918 .input{
1922 .input{
1919 display: table-cell;
1923 display: table-cell;
1920 padding: @padding/2;
1924 padding: @padding/2;
1921
1925
1922 input{
1926 input{
1923 min-width: 29em;
1927 min-width: 29em;
1924 padding: @padding/4;
1928 padding: @padding/4;
1925 }
1929 }
1926 }
1930 }
1927 .statistics, .downloads{
1931 .statistics, .downloads{
1928 .disabled{
1932 .disabled{
1929 color: @grey4;
1933 color: @grey4;
1930 }
1934 }
1931 }
1935 }
1932 }
1936 }
1933 }
1937 }
1934
1938
1935 #summary{
1939 #summary{
1936 width: 70%;
1940 width: 70%;
1937 }
1941 }
1938
1942
1939
1943
1940 // Journal
1944 // Journal
1941 .journal.title {
1945 .journal.title {
1942 h5 {
1946 h5 {
1943 float: left;
1947 float: left;
1944 margin: 0;
1948 margin: 0;
1945 width: 70%;
1949 width: 70%;
1946 }
1950 }
1947
1951
1948 ul {
1952 ul {
1949 float: right;
1953 float: right;
1950 display: inline-block;
1954 display: inline-block;
1951 margin: 0;
1955 margin: 0;
1952 width: 30%;
1956 width: 30%;
1953 text-align: right;
1957 text-align: right;
1954
1958
1955 li {
1959 li {
1956 display: inline;
1960 display: inline;
1957 font-size: @journal-fontsize;
1961 font-size: @journal-fontsize;
1958 line-height: 1em;
1962 line-height: 1em;
1959
1963
1960 list-style-type: none;
1964 list-style-type: none;
1961 }
1965 }
1962 }
1966 }
1963 }
1967 }
1964
1968
1965 .filterexample {
1969 .filterexample {
1966 position: absolute;
1970 position: absolute;
1967 top: 95px;
1971 top: 95px;
1968 left: @contentpadding;
1972 left: @contentpadding;
1969 color: @rcblue;
1973 color: @rcblue;
1970 font-size: 11px;
1974 font-size: 11px;
1971 font-family: @text-regular;
1975 font-family: @text-regular;
1972 cursor: help;
1976 cursor: help;
1973
1977
1974 &:hover {
1978 &:hover {
1975 color: @rcdarkblue;
1979 color: @rcdarkblue;
1976 }
1980 }
1977
1981
1978 @media (max-width:768px) {
1982 @media (max-width:768px) {
1979 position: relative;
1983 position: relative;
1980 top: auto;
1984 top: auto;
1981 left: auto;
1985 left: auto;
1982 display: block;
1986 display: block;
1983 }
1987 }
1984 }
1988 }
1985
1989
1986
1990
1987 #journal{
1991 #journal{
1988 margin-bottom: @space;
1992 margin-bottom: @space;
1989
1993
1990 .journal_day{
1994 .journal_day{
1991 margin-bottom: @textmargin/2;
1995 margin-bottom: @textmargin/2;
1992 padding-bottom: @textmargin/2;
1996 padding-bottom: @textmargin/2;
1993 font-size: @journal-fontsize;
1997 font-size: @journal-fontsize;
1994 border-bottom: @border-thickness solid @border-default-color;
1998 border-bottom: @border-thickness solid @border-default-color;
1995 }
1999 }
1996
2000
1997 .journal_container{
2001 .journal_container{
1998 margin-bottom: @space;
2002 margin-bottom: @space;
1999
2003
2000 .journal_user{
2004 .journal_user{
2001 display: inline-block;
2005 display: inline-block;
2002 }
2006 }
2003 .journal_action_container{
2007 .journal_action_container{
2004 display: block;
2008 display: block;
2005 margin-top: @textmargin;
2009 margin-top: @textmargin;
2006
2010
2007 div{
2011 div{
2008 display: inline;
2012 display: inline;
2009 }
2013 }
2010
2014
2011 div.journal_action_params{
2015 div.journal_action_params{
2012 display: block;
2016 display: block;
2013 }
2017 }
2014
2018
2015 div.journal_repo:after{
2019 div.journal_repo:after{
2016 content: "\A";
2020 content: "\A";
2017 white-space: pre;
2021 white-space: pre;
2018 }
2022 }
2019
2023
2020 div.date{
2024 div.date{
2021 display: block;
2025 display: block;
2022 margin-bottom: @textmargin;
2026 margin-bottom: @textmargin;
2023 }
2027 }
2024 }
2028 }
2025 }
2029 }
2026 }
2030 }
2027
2031
2028 // Files
2032 // Files
2029 .edit-file-title {
2033 .edit-file-title {
2030 border-bottom: @border-thickness solid @border-default-color;
2034 border-bottom: @border-thickness solid @border-default-color;
2031
2035
2032 .breadcrumbs {
2036 .breadcrumbs {
2033 margin-bottom: 0;
2037 margin-bottom: 0;
2034 }
2038 }
2035 }
2039 }
2036
2040
2037 .edit-file-fieldset {
2041 .edit-file-fieldset {
2038 margin-top: @sidebarpadding;
2042 margin-top: @sidebarpadding;
2039
2043
2040 .fieldset {
2044 .fieldset {
2041 .left-label {
2045 .left-label {
2042 width: 13%;
2046 width: 13%;
2043 }
2047 }
2044 .right-content {
2048 .right-content {
2045 width: 87%;
2049 width: 87%;
2046 max-width: 100%;
2050 max-width: 100%;
2047 }
2051 }
2048 .filename-label {
2052 .filename-label {
2049 margin-top: 13px;
2053 margin-top: 13px;
2050 }
2054 }
2051 .commit-message-label {
2055 .commit-message-label {
2052 margin-top: 4px;
2056 margin-top: 4px;
2053 }
2057 }
2054 .file-upload-input {
2058 .file-upload-input {
2055 input {
2059 input {
2056 display: none;
2060 display: none;
2057 }
2061 }
2058 margin-top: 10px;
2062 margin-top: 10px;
2059 }
2063 }
2060 .file-upload-label {
2064 .file-upload-label {
2061 margin-top: 10px;
2065 margin-top: 10px;
2062 }
2066 }
2063 p {
2067 p {
2064 margin-top: 5px;
2068 margin-top: 5px;
2065 }
2069 }
2066
2070
2067 }
2071 }
2068 .custom-path-link {
2072 .custom-path-link {
2069 margin-left: 5px;
2073 margin-left: 5px;
2070 }
2074 }
2071 #commit {
2075 #commit {
2072 resize: vertical;
2076 resize: vertical;
2073 }
2077 }
2074 }
2078 }
2075
2079
2076 .delete-file-preview {
2080 .delete-file-preview {
2077 max-height: 250px;
2081 max-height: 250px;
2078 }
2082 }
2079
2083
2080 .new-file,
2084 .new-file,
2081 #filter_activate,
2085 #filter_activate,
2082 #filter_deactivate {
2086 #filter_deactivate {
2083 float: left;
2087 float: left;
2084 margin: 0 0 0 15px;
2088 margin: 0 0 0 15px;
2085 }
2089 }
2086
2090
2087 h3.files_location{
2091 h3.files_location{
2088 line-height: 2.4em;
2092 line-height: 2.4em;
2089 }
2093 }
2090
2094
2091 .browser-nav {
2095 .browser-nav {
2092 display: table;
2096 display: table;
2093 margin-bottom: @space;
2097 margin-bottom: @space;
2094
2098
2095
2099
2096 .info_box {
2100 .info_box {
2097 display: inline-table;
2101 display: inline-table;
2098 height: 2.5em;
2102 height: 2.5em;
2099
2103
2100 .browser-cur-rev, .info_box_elem {
2104 .browser-cur-rev, .info_box_elem {
2101 display: table-cell;
2105 display: table-cell;
2102 vertical-align: middle;
2106 vertical-align: middle;
2103 }
2107 }
2104
2108
2105 .info_box_elem {
2109 .info_box_elem {
2106 border-top: @border-thickness solid @rcblue;
2110 border-top: @border-thickness solid @rcblue;
2107 border-bottom: @border-thickness solid @rcblue;
2111 border-bottom: @border-thickness solid @rcblue;
2108
2112
2109 #at_rev, a {
2113 #at_rev, a {
2110 padding: 0.6em 0.9em;
2114 padding: 0.6em 0.9em;
2111 margin: 0;
2115 margin: 0;
2112 .box-shadow(none);
2116 .box-shadow(none);
2113 border: 0;
2117 border: 0;
2114 height: 12px;
2118 height: 12px;
2115 }
2119 }
2116
2120
2117 input#at_rev {
2121 input#at_rev {
2118 max-width: 50px;
2122 max-width: 50px;
2119 text-align: right;
2123 text-align: right;
2120 }
2124 }
2121
2125
2122 &.previous {
2126 &.previous {
2123 border: @border-thickness solid @rcblue;
2127 border: @border-thickness solid @rcblue;
2124 .disabled {
2128 .disabled {
2125 color: @grey4;
2129 color: @grey4;
2126 cursor: not-allowed;
2130 cursor: not-allowed;
2127 }
2131 }
2128 }
2132 }
2129
2133
2130 &.next {
2134 &.next {
2131 border: @border-thickness solid @rcblue;
2135 border: @border-thickness solid @rcblue;
2132 .disabled {
2136 .disabled {
2133 color: @grey4;
2137 color: @grey4;
2134 cursor: not-allowed;
2138 cursor: not-allowed;
2135 }
2139 }
2136 }
2140 }
2137 }
2141 }
2138
2142
2139 .browser-cur-rev {
2143 .browser-cur-rev {
2140
2144
2141 span{
2145 span{
2142 margin: 0;
2146 margin: 0;
2143 color: @rcblue;
2147 color: @rcblue;
2144 height: 12px;
2148 height: 12px;
2145 display: inline-block;
2149 display: inline-block;
2146 padding: 0.7em 1em ;
2150 padding: 0.7em 1em ;
2147 border: @border-thickness solid @rcblue;
2151 border: @border-thickness solid @rcblue;
2148 margin-right: @padding;
2152 margin-right: @padding;
2149 }
2153 }
2150 }
2154 }
2151 }
2155 }
2152
2156
2153 .search_activate {
2157 .search_activate {
2154 display: table-cell;
2158 display: table-cell;
2155 vertical-align: middle;
2159 vertical-align: middle;
2156
2160
2157 input, label{
2161 input, label{
2158 margin: 0;
2162 margin: 0;
2159 padding: 0;
2163 padding: 0;
2160 }
2164 }
2161
2165
2162 input{
2166 input{
2163 margin-left: @textmargin;
2167 margin-left: @textmargin;
2164 }
2168 }
2165
2169
2166 }
2170 }
2167 }
2171 }
2168
2172
2169 .browser-cur-rev{
2173 .browser-cur-rev{
2170 margin-bottom: @textmargin;
2174 margin-bottom: @textmargin;
2171 }
2175 }
2172
2176
2173 #node_filter_box_loading{
2177 #node_filter_box_loading{
2174 .info_text;
2178 .info_text;
2175 }
2179 }
2176
2180
2177 .browser-search {
2181 .browser-search {
2178 margin: -25px 0px 5px 0px;
2182 margin: -25px 0px 5px 0px;
2179 }
2183 }
2180
2184
2181 .node-filter {
2185 .node-filter {
2182 font-size: @repo-title-fontsize;
2186 font-size: @repo-title-fontsize;
2183 padding: 4px 0px 0px 0px;
2187 padding: 4px 0px 0px 0px;
2184
2188
2185 .node-filter-path {
2189 .node-filter-path {
2186 float: left;
2190 float: left;
2187 color: @grey4;
2191 color: @grey4;
2188 }
2192 }
2189 .node-filter-input {
2193 .node-filter-input {
2190 float: left;
2194 float: left;
2191 margin: -2px 0px 0px 2px;
2195 margin: -2px 0px 0px 2px;
2192 input {
2196 input {
2193 padding: 2px;
2197 padding: 2px;
2194 border: none;
2198 border: none;
2195 font-size: @repo-title-fontsize;
2199 font-size: @repo-title-fontsize;
2196 }
2200 }
2197 }
2201 }
2198 }
2202 }
2199
2203
2200
2204
2201 .browser-result{
2205 .browser-result{
2202 td a{
2206 td a{
2203 margin-left: 0.5em;
2207 margin-left: 0.5em;
2204 display: inline-block;
2208 display: inline-block;
2205
2209
2206 em {
2210 em {
2207 font-weight: @text-bold-weight;
2211 font-weight: @text-bold-weight;
2208 font-family: @text-bold;
2212 font-family: @text-bold;
2209 }
2213 }
2210 }
2214 }
2211 }
2215 }
2212
2216
2213 .browser-highlight{
2217 .browser-highlight{
2214 background-color: @grey5-alpha;
2218 background-color: @grey5-alpha;
2215 }
2219 }
2216
2220
2217
2221
2218 // Search
2222 // Search
2219
2223
2220 .search-form{
2224 .search-form{
2221 #q {
2225 #q {
2222 width: @search-form-width;
2226 width: @search-form-width;
2223 }
2227 }
2224 .fields{
2228 .fields{
2225 margin: 0 0 @space;
2229 margin: 0 0 @space;
2226 }
2230 }
2227
2231
2228 label{
2232 label{
2229 display: inline-block;
2233 display: inline-block;
2230 margin-right: @textmargin;
2234 margin-right: @textmargin;
2231 padding-top: 0.25em;
2235 padding-top: 0.25em;
2232 }
2236 }
2233
2237
2234
2238
2235 .results{
2239 .results{
2236 clear: both;
2240 clear: both;
2237 margin: 0 0 @padding;
2241 margin: 0 0 @padding;
2238 }
2242 }
2239
2243
2240 .search-tags {
2244 .search-tags {
2241 padding: 5px 0;
2245 padding: 5px 0;
2242 }
2246 }
2243 }
2247 }
2244
2248
2245 div.search-feedback-items {
2249 div.search-feedback-items {
2246 display: inline-block;
2250 display: inline-block;
2247 }
2251 }
2248
2252
2249 div.search-code-body {
2253 div.search-code-body {
2250 background-color: #ffffff; padding: 5px 0 5px 10px;
2254 background-color: #ffffff; padding: 5px 0 5px 10px;
2251 pre {
2255 pre {
2252 .match { background-color: #faffa6;}
2256 .match { background-color: #faffa6;}
2253 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2257 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2254 }
2258 }
2255 }
2259 }
2256
2260
2257 .expand_commit.search {
2261 .expand_commit.search {
2258 .show_more.open {
2262 .show_more.open {
2259 height: auto;
2263 height: auto;
2260 max-height: none;
2264 max-height: none;
2261 }
2265 }
2262 }
2266 }
2263
2267
2264 .search-results {
2268 .search-results {
2265
2269
2266 h2 {
2270 h2 {
2267 margin-bottom: 0;
2271 margin-bottom: 0;
2268 }
2272 }
2269 .codeblock {
2273 .codeblock {
2270 border: none;
2274 border: none;
2271 background: transparent;
2275 background: transparent;
2272 }
2276 }
2273
2277
2274 .codeblock-header {
2278 .codeblock-header {
2275 border: none;
2279 border: none;
2276 background: transparent;
2280 background: transparent;
2277 }
2281 }
2278
2282
2279 .code-body {
2283 .code-body {
2280 border: @border-thickness solid @border-default-color;
2284 border: @border-thickness solid @border-default-color;
2281 .border-radius(@border-radius);
2285 .border-radius(@border-radius);
2282 }
2286 }
2283
2287
2284 .td-commit {
2288 .td-commit {
2285 &:extend(pre);
2289 &:extend(pre);
2286 border-bottom: @border-thickness solid @border-default-color;
2290 border-bottom: @border-thickness solid @border-default-color;
2287 }
2291 }
2288
2292
2289 .message {
2293 .message {
2290 height: auto;
2294 height: auto;
2291 max-width: 350px;
2295 max-width: 350px;
2292 white-space: normal;
2296 white-space: normal;
2293 text-overflow: initial;
2297 text-overflow: initial;
2294 overflow: visible;
2298 overflow: visible;
2295
2299
2296 .match { background-color: #faffa6;}
2300 .match { background-color: #faffa6;}
2297 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2301 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2298 }
2302 }
2299
2303
2300 }
2304 }
2301
2305
2302 table.rctable td.td-search-results div {
2306 table.rctable td.td-search-results div {
2303 max-width: 100%;
2307 max-width: 100%;
2304 }
2308 }
2305
2309
2306 #tip-box, .tip-box{
2310 #tip-box, .tip-box{
2307 padding: @menupadding/2;
2311 padding: @menupadding/2;
2308 display: block;
2312 display: block;
2309 border: @border-thickness solid @border-highlight-color;
2313 border: @border-thickness solid @border-highlight-color;
2310 .border-radius(@border-radius);
2314 .border-radius(@border-radius);
2311 background-color: white;
2315 background-color: white;
2312 z-index: 99;
2316 z-index: 99;
2313 white-space: pre-wrap;
2317 white-space: pre-wrap;
2314 }
2318 }
2315
2319
2316 #linktt {
2320 #linktt {
2317 width: 79px;
2321 width: 79px;
2318 }
2322 }
2319
2323
2320 #help_kb .modal-content{
2324 #help_kb .modal-content{
2321 max-width: 750px;
2325 max-width: 750px;
2322 margin: 10% auto;
2326 margin: 10% auto;
2323
2327
2324 table{
2328 table{
2325 td,th{
2329 td,th{
2326 border-bottom: none;
2330 border-bottom: none;
2327 line-height: 2.5em;
2331 line-height: 2.5em;
2328 }
2332 }
2329 th{
2333 th{
2330 padding-bottom: @textmargin/2;
2334 padding-bottom: @textmargin/2;
2331 }
2335 }
2332 td.keys{
2336 td.keys{
2333 text-align: center;
2337 text-align: center;
2334 }
2338 }
2335 }
2339 }
2336
2340
2337 .block-left{
2341 .block-left{
2338 width: 45%;
2342 width: 45%;
2339 margin-right: 5%;
2343 margin-right: 5%;
2340 }
2344 }
2341 .modal-footer{
2345 .modal-footer{
2342 clear: both;
2346 clear: both;
2343 }
2347 }
2344 .key.tag{
2348 .key.tag{
2345 padding: 0.5em;
2349 padding: 0.5em;
2346 background-color: @rcblue;
2350 background-color: @rcblue;
2347 color: white;
2351 color: white;
2348 border-color: @rcblue;
2352 border-color: @rcblue;
2349 .box-shadow(none);
2353 .box-shadow(none);
2350 }
2354 }
2351 }
2355 }
2352
2356
2353
2357
2354
2358
2355 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2359 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2356
2360
2357 @import 'statistics-graph';
2361 @import 'statistics-graph';
2358 @import 'tables';
2362 @import 'tables';
2359 @import 'forms';
2363 @import 'forms';
2360 @import 'diff';
2364 @import 'diff';
2361 @import 'summary';
2365 @import 'summary';
2362 @import 'navigation';
2366 @import 'navigation';
2363
2367
2364 //--- SHOW/HIDE SECTIONS --//
2368 //--- SHOW/HIDE SECTIONS --//
2365
2369
2366 .btn-collapse {
2370 .btn-collapse {
2367 float: right;
2371 float: right;
2368 text-align: right;
2372 text-align: right;
2369 font-family: @text-light;
2373 font-family: @text-light;
2370 font-size: @basefontsize;
2374 font-size: @basefontsize;
2371 cursor: pointer;
2375 cursor: pointer;
2372 border: none;
2376 border: none;
2373 color: @rcblue;
2377 color: @rcblue;
2374 }
2378 }
2375
2379
2376 table.rctable,
2380 table.rctable,
2377 table.dataTable {
2381 table.dataTable {
2378 .btn-collapse {
2382 .btn-collapse {
2379 float: right;
2383 float: right;
2380 text-align: right;
2384 text-align: right;
2381 }
2385 }
2382 }
2386 }
2383
2387
2384 table.rctable {
2388 table.rctable {
2385 &.permissions {
2389 &.permissions {
2386
2390
2387 th.td-owner {
2391 th.td-owner {
2388 padding: 0;
2392 padding: 0;
2389 }
2393 }
2390
2394
2391 th {
2395 th {
2392 font-weight: normal;
2396 font-weight: normal;
2393 padding: 0 5px;
2397 padding: 0 5px;
2394 }
2398 }
2395
2399
2396 }
2400 }
2397 }
2401 }
2398
2402
2399
2403
2400 // TODO: johbo: Fix for IE10, this avoids that we see a border
2404 // TODO: johbo: Fix for IE10, this avoids that we see a border
2401 // and padding around checkboxes and radio boxes. Move to the right place,
2405 // and padding around checkboxes and radio boxes. Move to the right place,
2402 // or better: Remove this once we did the form refactoring.
2406 // or better: Remove this once we did the form refactoring.
2403 input[type=checkbox],
2407 input[type=checkbox],
2404 input[type=radio] {
2408 input[type=radio] {
2405 padding: 0;
2409 padding: 0;
2406 border: none;
2410 border: none;
2407 }
2411 }
2408
2412
2409 .toggle-ajax-spinner{
2413 .toggle-ajax-spinner{
2410 height: 16px;
2414 height: 16px;
2411 width: 16px;
2415 width: 16px;
2412 }
2416 }
2413
2417
2414
2418
2415 .markup-form .clearfix {
2419 .markup-form .clearfix {
2416 .border-radius(@border-radius);
2420 .border-radius(@border-radius);
2417 margin: 0px;
2421 margin: 0px;
2418 }
2422 }
2419
2423
2420 .markup-form-area {
2424 .markup-form-area {
2421 padding: 8px 12px;
2425 padding: 8px 12px;
2422 border: 1px solid @grey4;
2426 border: 1px solid @grey4;
2423 .border-radius(@border-radius);
2427 .border-radius(@border-radius);
2424 }
2428 }
2425
2429
2426 .markup-form-area-header .nav-links {
2430 .markup-form-area-header .nav-links {
2427 display: flex;
2431 display: flex;
2428 flex-flow: row wrap;
2432 flex-flow: row wrap;
2429 -webkit-flex-flow: row wrap;
2433 -webkit-flex-flow: row wrap;
2430 width: 100%;
2434 width: 100%;
2431 }
2435 }
2432
2436
2433 .markup-form-area-footer {
2437 .markup-form-area-footer {
2434 display: flex;
2438 display: flex;
2435 }
2439 }
2436
2440
2437 .markup-form-area-footer .toolbar {
2441 .markup-form-area-footer .toolbar {
2438
2442
2439 }
2443 }
2440
2444
2441 // markup Form
2445 // markup Form
2442 div.markup-form {
2446 div.markup-form {
2443 margin-top: 20px;
2447 margin-top: 20px;
2444 }
2448 }
2445
2449
2446 .markup-form strong {
2450 .markup-form strong {
2447 display: block;
2451 display: block;
2448 margin-bottom: 15px;
2452 margin-bottom: 15px;
2449 }
2453 }
2450
2454
2451 .markup-form textarea {
2455 .markup-form textarea {
2452 width: 100%;
2456 width: 100%;
2453 height: 100px;
2457 height: 100px;
2454 font-family: @text-monospace;
2458 font-family: @text-monospace;
2455 }
2459 }
2456
2460
2457 form.markup-form {
2461 form.markup-form {
2458 margin-top: 10px;
2462 margin-top: 10px;
2459 margin-left: 10px;
2463 margin-left: 10px;
2460 }
2464 }
2461
2465
2462 .markup-form .comment-block-ta,
2466 .markup-form .comment-block-ta,
2463 .markup-form .preview-box {
2467 .markup-form .preview-box {
2464 .border-radius(@border-radius);
2468 .border-radius(@border-radius);
2465 .box-sizing(border-box);
2469 .box-sizing(border-box);
2466 background-color: white;
2470 background-color: white;
2467 }
2471 }
2468
2472
2469 .markup-form .preview-box.unloaded {
2473 .markup-form .preview-box.unloaded {
2470 height: 50px;
2474 height: 50px;
2471 text-align: center;
2475 text-align: center;
2472 padding: 20px;
2476 padding: 20px;
2473 background-color: white;
2477 background-color: white;
2474 }
2478 }
@@ -1,830 +1,832 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <%include file="/ejs_templates/templates.html"/>
4 <%include file="/ejs_templates/templates.html"/>
5
5
6 <div class="outerwrapper">
6 <div class="outerwrapper">
7 <!-- HEADER -->
7 <!-- HEADER -->
8 <div class="header">
8 <div class="header">
9 <div id="header-inner" class="wrapper">
9 <div id="header-inner" class="wrapper">
10 <div id="logo">
10 <div id="logo">
11 <div class="logo-wrapper">
11 <div class="logo-wrapper">
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
12 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
13 </div>
13 </div>
14 %if c.rhodecode_name:
14 % if c.rhodecode_name:
15 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
15 <div class="branding">
16 %endif
16 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
17 </div>
18 % endif
17 </div>
19 </div>
18 <!-- MENU BAR NAV -->
20 <!-- MENU BAR NAV -->
19 ${self.menu_bar_nav()}
21 ${self.menu_bar_nav()}
20 <!-- END MENU BAR NAV -->
22 <!-- END MENU BAR NAV -->
21 </div>
23 </div>
22 </div>
24 </div>
23 ${self.menu_bar_subnav()}
25 ${self.menu_bar_subnav()}
24 <!-- END HEADER -->
26 <!-- END HEADER -->
25
27
26 <!-- CONTENT -->
28 <!-- CONTENT -->
27 <div id="content" class="wrapper">
29 <div id="content" class="wrapper">
28
30
29 <rhodecode-toast id="notifications"></rhodecode-toast>
31 <rhodecode-toast id="notifications"></rhodecode-toast>
30
32
31 <div class="main">
33 <div class="main">
32 ${next.main()}
34 ${next.main()}
33 </div>
35 </div>
34 </div>
36 </div>
35 <!-- END CONTENT -->
37 <!-- END CONTENT -->
36
38
37 </div>
39 </div>
38 <!-- FOOTER -->
40 <!-- FOOTER -->
39 <div id="footer">
41 <div id="footer">
40 <div id="footer-inner" class="title wrapper">
42 <div id="footer-inner" class="title wrapper">
41 <div>
43 <div>
42 <p class="footer-link-right">
44 <p class="footer-link-right">
43 % if c.visual.show_version:
45 % if c.visual.show_version:
44 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
46 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
45 % endif
47 % endif
46 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
48 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
47 % if c.visual.rhodecode_support_url:
49 % if c.visual.rhodecode_support_url:
48 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
50 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
49 % endif
51 % endif
50 </p>
52 </p>
51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
53 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
52 <p class="server-instance" style="display:${sid}">
54 <p class="server-instance" style="display:${sid}">
53 ## display hidden instance ID if specially defined
55 ## display hidden instance ID if specially defined
54 % if c.rhodecode_instanceid:
56 % if c.rhodecode_instanceid:
55 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
57 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
56 % endif
58 % endif
57 </p>
59 </p>
58 </div>
60 </div>
59 </div>
61 </div>
60 </div>
62 </div>
61
63
62 <!-- END FOOTER -->
64 <!-- END FOOTER -->
63
65
64 ### MAKO DEFS ###
66 ### MAKO DEFS ###
65
67
66 <%def name="menu_bar_subnav()">
68 <%def name="menu_bar_subnav()">
67 </%def>
69 </%def>
68
70
69 <%def name="breadcrumbs(class_='breadcrumbs')">
71 <%def name="breadcrumbs(class_='breadcrumbs')">
70 <div class="${class_}">
72 <div class="${class_}">
71 ${self.breadcrumbs_links()}
73 ${self.breadcrumbs_links()}
72 </div>
74 </div>
73 </%def>
75 </%def>
74
76
75 <%def name="admin_menu()">
77 <%def name="admin_menu()">
76 <ul class="admin_menu submenu">
78 <ul class="admin_menu submenu">
77 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
79 <li><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
78 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
80 <li><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
79 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
81 <li><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
80 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
82 <li><a href="${h.route_path('users')}">${_('Users')}</a></li>
81 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
83 <li><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
82 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
84 <li><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
83 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
85 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
84 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
86 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
85 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
87 <li><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
86 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
88 <li class="last"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
87 </ul>
89 </ul>
88 </%def>
90 </%def>
89
91
90
92
91 <%def name="dt_info_panel(elements)">
93 <%def name="dt_info_panel(elements)">
92 <dl class="dl-horizontal">
94 <dl class="dl-horizontal">
93 %for dt, dd, title, show_items in elements:
95 %for dt, dd, title, show_items in elements:
94 <dt>${dt}:</dt>
96 <dt>${dt}:</dt>
95 <dd title="${h.tooltip(title)}">
97 <dd title="${h.tooltip(title)}">
96 %if callable(dd):
98 %if callable(dd):
97 ## allow lazy evaluation of elements
99 ## allow lazy evaluation of elements
98 ${dd()}
100 ${dd()}
99 %else:
101 %else:
100 ${dd}
102 ${dd}
101 %endif
103 %endif
102 %if show_items:
104 %if show_items:
103 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
105 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
104 %endif
106 %endif
105 </dd>
107 </dd>
106
108
107 %if show_items:
109 %if show_items:
108 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
110 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
109 %for item in show_items:
111 %for item in show_items:
110 <dt></dt>
112 <dt></dt>
111 <dd>${item}</dd>
113 <dd>${item}</dd>
112 %endfor
114 %endfor
113 </div>
115 </div>
114 %endif
116 %endif
115
117
116 %endfor
118 %endfor
117 </dl>
119 </dl>
118 </%def>
120 </%def>
119
121
120
122
121 <%def name="gravatar(email, size=16)">
123 <%def name="gravatar(email, size=16)">
122 <%
124 <%
123 if (size > 16):
125 if (size > 16):
124 gravatar_class = 'gravatar gravatar-large'
126 gravatar_class = 'gravatar gravatar-large'
125 else:
127 else:
126 gravatar_class = 'gravatar'
128 gravatar_class = 'gravatar'
127 %>
129 %>
128 <%doc>
130 <%doc>
129 TODO: johbo: For now we serve double size images to make it smooth
131 TODO: johbo: For now we serve double size images to make it smooth
130 for retina. This is how it worked until now. Should be replaced
132 for retina. This is how it worked until now. Should be replaced
131 with a better solution at some point.
133 with a better solution at some point.
132 </%doc>
134 </%doc>
133 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
135 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
134 </%def>
136 </%def>
135
137
136
138
137 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
139 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
138 <% email = h.email_or_none(contact) %>
140 <% email = h.email_or_none(contact) %>
139 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
141 <div class="rc-user tooltip" title="${h.tooltip(h.author_string(email))}">
140 ${self.gravatar(email, size)}
142 ${self.gravatar(email, size)}
141 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
143 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
142 </div>
144 </div>
143 </%def>
145 </%def>
144
146
145
147
146 ## admin menu used for people that have some admin resources
148 ## admin menu used for people that have some admin resources
147 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
149 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
148 <ul class="submenu">
150 <ul class="submenu">
149 %if repositories:
151 %if repositories:
150 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
152 <li class="local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
151 %endif
153 %endif
152 %if repository_groups:
154 %if repository_groups:
153 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
155 <li class="local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
154 %endif
156 %endif
155 %if user_groups:
157 %if user_groups:
156 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
158 <li class="local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
157 %endif
159 %endif
158 </ul>
160 </ul>
159 </%def>
161 </%def>
160
162
161 <%def name="repo_page_title(repo_instance)">
163 <%def name="repo_page_title(repo_instance)">
162 <div class="title-content">
164 <div class="title-content">
163 <div class="title-main">
165 <div class="title-main">
164 ## SVN/HG/GIT icons
166 ## SVN/HG/GIT icons
165 %if h.is_hg(repo_instance):
167 %if h.is_hg(repo_instance):
166 <i class="icon-hg"></i>
168 <i class="icon-hg"></i>
167 %endif
169 %endif
168 %if h.is_git(repo_instance):
170 %if h.is_git(repo_instance):
169 <i class="icon-git"></i>
171 <i class="icon-git"></i>
170 %endif
172 %endif
171 %if h.is_svn(repo_instance):
173 %if h.is_svn(repo_instance):
172 <i class="icon-svn"></i>
174 <i class="icon-svn"></i>
173 %endif
175 %endif
174
176
175 ## public/private
177 ## public/private
176 %if repo_instance.private:
178 %if repo_instance.private:
177 <i class="icon-repo-private"></i>
179 <i class="icon-repo-private"></i>
178 %else:
180 %else:
179 <i class="icon-repo-public"></i>
181 <i class="icon-repo-public"></i>
180 %endif
182 %endif
181
183
182 ## repo name with group name
184 ## repo name with group name
183 ${h.breadcrumb_repo_link(repo_instance)}
185 ${h.breadcrumb_repo_link(repo_instance)}
184
186
185 </div>
187 </div>
186
188
187 ## FORKED
189 ## FORKED
188 %if repo_instance.fork:
190 %if repo_instance.fork:
189 <p>
191 <p>
190 <i class="icon-code-fork"></i> ${_('Fork of')}
192 <i class="icon-code-fork"></i> ${_('Fork of')}
191 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
193 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
192 </p>
194 </p>
193 %endif
195 %endif
194
196
195 ## IMPORTED FROM REMOTE
197 ## IMPORTED FROM REMOTE
196 %if repo_instance.clone_uri:
198 %if repo_instance.clone_uri:
197 <p>
199 <p>
198 <i class="icon-code-fork"></i> ${_('Clone from')}
200 <i class="icon-code-fork"></i> ${_('Clone from')}
199 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
201 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
200 </p>
202 </p>
201 %endif
203 %endif
202
204
203 ## LOCKING STATUS
205 ## LOCKING STATUS
204 %if repo_instance.locked[0]:
206 %if repo_instance.locked[0]:
205 <p class="locking_locked">
207 <p class="locking_locked">
206 <i class="icon-repo-lock"></i>
208 <i class="icon-repo-lock"></i>
207 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
209 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
208 </p>
210 </p>
209 %elif repo_instance.enable_locking:
211 %elif repo_instance.enable_locking:
210 <p class="locking_unlocked">
212 <p class="locking_unlocked">
211 <i class="icon-repo-unlock"></i>
213 <i class="icon-repo-unlock"></i>
212 ${_('Repository not locked. Pull repository to lock it.')}
214 ${_('Repository not locked. Pull repository to lock it.')}
213 </p>
215 </p>
214 %endif
216 %endif
215
217
216 </div>
218 </div>
217 </%def>
219 </%def>
218
220
219 <%def name="repo_menu(active=None)">
221 <%def name="repo_menu(active=None)">
220 <%
222 <%
221 def is_active(selected):
223 def is_active(selected):
222 if selected == active:
224 if selected == active:
223 return "active"
225 return "active"
224 %>
226 %>
225
227
226 <!--- CONTEXT BAR -->
228 <!--- CONTEXT BAR -->
227 <div id="context-bar">
229 <div id="context-bar">
228 <div class="wrapper">
230 <div class="wrapper">
229 <ul id="context-pages" class="navigation horizontal-list">
231 <ul id="context-pages" class="navigation horizontal-list">
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>
232 <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 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
233 <li class="${is_active('changelog')}"><a class="menulink" href="${h.route_path('repo_changelog', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
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>
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>
233 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
235 <li class="${is_active('compare')}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
234 <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>
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>
235
237
236 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
238 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
237 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
239 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
238 <li class="${is_active('showpullrequest')}">
240 <li class="${is_active('showpullrequest')}">
239 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
241 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
240 %if c.repository_pull_requests:
242 %if c.repository_pull_requests:
241 <span class="pr_notifications">${c.repository_pull_requests}</span>
243 <span class="pr_notifications">${c.repository_pull_requests}</span>
242 %endif
244 %endif
243 <div class="menulabel">${_('Pull Requests')}</div>
245 <div class="menulabel">${_('Pull Requests')}</div>
244 </a>
246 </a>
245 </li>
247 </li>
246 %endif
248 %endif
247
249
248 <li class="${is_active('options')}">
250 <li class="${is_active('options')}">
249 <a class="menulink dropdown">
251 <a class="menulink dropdown">
250 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
252 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
251 </a>
253 </a>
252 <ul class="submenu">
254 <ul class="submenu">
253 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
255 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
254 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Repository Settings')}</a></li>
256 <li><a href="${h.route_path('edit_repo',repo_name=c.repo_name)}">${_('Repository Settings')}</a></li>
255 %endif
257 %endif
256 %if c.rhodecode_db_repo.fork:
258 %if c.rhodecode_db_repo.fork:
257 <li>
259 <li>
258 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
260 <a title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
259 href="${h.route_path('repo_compare',
261 href="${h.route_path('repo_compare',
260 repo_name=c.rhodecode_db_repo.fork.repo_name,
262 repo_name=c.rhodecode_db_repo.fork.repo_name,
261 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
263 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
262 source_ref=c.rhodecode_db_repo.landing_rev[1],
264 source_ref=c.rhodecode_db_repo.landing_rev[1],
263 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
265 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
264 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
266 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
265 _query=dict(merge=1))}"
267 _query=dict(merge=1))}"
266 >
268 >
267 ${_('Compare fork')}
269 ${_('Compare fork')}
268 </a>
270 </a>
269 </li>
271 </li>
270 %endif
272 %endif
271
273
272 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
274 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
273 %if c.rhodecode_db_repo.locked[0]:
275 %if c.rhodecode_db_repo.locked[0]:
274 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
276 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
275 %else:
277 %else:
276 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
278 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
277 %endif
279 %endif
278 %endif
280 %endif
279 %if c.rhodecode_user.username != h.DEFAULT_USER:
281 %if c.rhodecode_user.username != h.DEFAULT_USER:
280 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
282 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
281 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
283 <li><a href="${h.route_path('repo_fork_new',repo_name=c.repo_name)}">${_('Fork')}</a></li>
282 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
284 <li><a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
283 %endif
285 %endif
284 %endif
286 %endif
285 </ul>
287 </ul>
286 </li>
288 </li>
287 </ul>
289 </ul>
288 </div>
290 </div>
289 <div class="clear"></div>
291 <div class="clear"></div>
290 </div>
292 </div>
291 % if c.rhodecode_db_repo.archived:
293 % if c.rhodecode_db_repo.archived:
292 <div class="alert alert-warning text-center">
294 <div class="alert alert-warning text-center">
293 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
295 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
294 </div>
296 </div>
295 % endif
297 % endif
296 <!--- END CONTEXT BAR -->
298 <!--- END CONTEXT BAR -->
297
299
298 </%def>
300 </%def>
299
301
300 <%def name="repo_group_page_title(repo_group_instance)">
302 <%def name="repo_group_page_title(repo_group_instance)">
301 <div class="title-content">
303 <div class="title-content">
302 <div class="title-main">
304 <div class="title-main">
303 ## Repository Group icon
305 ## Repository Group icon
304 <i class="icon-folder-close"></i>
306 <i class="icon-folder-close"></i>
305
307
306 ## repo name with group name
308 ## repo name with group name
307 ${h.breadcrumb_repo_group_link(repo_group_instance)}
309 ${h.breadcrumb_repo_group_link(repo_group_instance)}
308 </div>
310 </div>
309
311
310 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
312 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
311 <div class="repo-group-desc">
313 <div class="repo-group-desc">
312 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
314 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
313 </div>
315 </div>
314
316
315 </div>
317 </div>
316 </%def>
318 </%def>
317
319
318 <%def name="repo_group_menu(active=None)">
320 <%def name="repo_group_menu(active=None)">
319 <%
321 <%
320 def is_active(selected):
322 def is_active(selected):
321 if selected == active:
323 if selected == active:
322 return "active"
324 return "active"
323
325
324 is_admin = h.HasPermissionAny('hg.admin')('can create repos index page')
326 is_admin = h.HasPermissionAny('hg.admin')('can create repos index page')
325
327
326 gr_name = c.repo_group.group_name if c.repo_group else None
328 gr_name = c.repo_group.group_name if c.repo_group else None
327 # create repositories with write permission on group is set to true
329 # create repositories with write permission on group is set to true
328 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
330 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
329 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
331 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
330 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
332 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
331
333
332 %>
334 %>
333
335
334 <!--- CONTEXT BAR -->
336 <!--- CONTEXT BAR -->
335 <div id="context-bar">
337 <div id="context-bar">
336 <div class="wrapper">
338 <div class="wrapper">
337 <ul id="context-pages" class="navigation horizontal-list">
339 <ul id="context-pages" class="navigation horizontal-list">
338 <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>
340 <li class="${is_active('home')}"><a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a></li>
339 <li class="${is_active('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>
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>
340
342
341 <li class="${is_active('options')}">
343 <li class="${is_active('options')}">
342 <a class="menulink dropdown">
344 <a class="menulink dropdown">
343 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
345 <div class="menulabel">${_('Options')} <div class="show_more"></div></div>
344 </a>
346 </a>
345 <ul class="submenu">
347 <ul class="submenu">
346 %if is_admin or group_admin:
348 %if is_admin or group_admin:
347 <li><a href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}">${_('Group Settings')}</a></li>
349 <li><a href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}">${_('Group Settings')}</a></li>
348 %endif
350 %endif
349 %if is_admin or group_admin or (group_write and create_on_write):
351 %if is_admin or group_admin or (group_write and create_on_write):
350 <li><a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('Add Repository')}</a></li>
352 <li><a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('Add Repository')}</a></li>
351 %endif
353 %endif
352 %if is_admin or group_admin:
354 %if is_admin or group_admin:
353 <li><a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'Add Parent Group')}</a></li>
355 <li><a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'Add Parent Group')}</a></li>
354 %endif
356 %endif
355 </ul>
357 </ul>
356 </li>
358 </li>
357 </ul>
359 </ul>
358 </div>
360 </div>
359 <div class="clear"></div>
361 <div class="clear"></div>
360 </div>
362 </div>
361
363
362 <!--- END CONTEXT BAR -->
364 <!--- END CONTEXT BAR -->
363
365
364 </%def>
366 </%def>
365
367
366
368
367 <%def name="usermenu(active=False)">
369 <%def name="usermenu(active=False)">
368 ## USER MENU
370 ## USER MENU
369 <li id="quick_login_li" class="${'active' if active else ''}">
371 <li id="quick_login_li" class="${'active' if active else ''}">
370 % if c.rhodecode_user.username == h.DEFAULT_USER:
372 % if c.rhodecode_user.username == h.DEFAULT_USER:
371 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
373 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
372 ${gravatar(c.rhodecode_user.email, 20)}
374 ${gravatar(c.rhodecode_user.email, 20)}
373 <span class="user">
375 <span class="user">
374 <span>${_('Sign in')}</span>
376 <span>${_('Sign in')}</span>
375 </span>
377 </span>
376 </a>
378 </a>
377 % else:
379 % else:
378 ## logged in user
380 ## logged in user
379 <a id="quick_login_link" class="menulink childs">
381 <a id="quick_login_link" class="menulink childs">
380 ${gravatar(c.rhodecode_user.email, 20)}
382 ${gravatar(c.rhodecode_user.email, 20)}
381 <span class="user">
383 <span class="user">
382 <span class="menu_link_user">${c.rhodecode_user.username}</span>
384 <span class="menu_link_user">${c.rhodecode_user.username}</span>
383 <div class="show_more"></div>
385 <div class="show_more"></div>
384 </span>
386 </span>
385 </a>
387 </a>
386 ## subnav with menu for logged in user
388 ## subnav with menu for logged in user
387 <div class="user-menu submenu">
389 <div class="user-menu submenu">
388 <div id="quick_login">
390 <div id="quick_login">
389 %if c.rhodecode_user.username != h.DEFAULT_USER:
391 %if c.rhodecode_user.username != h.DEFAULT_USER:
390 <div class="">
392 <div class="">
391 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
393 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
392 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
394 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
393 <div class="email">${c.rhodecode_user.email}</div>
395 <div class="email">${c.rhodecode_user.email}</div>
394 </div>
396 </div>
395 <div class="">
397 <div class="">
396 <ol class="links">
398 <ol class="links">
397 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
399 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
398 % if c.rhodecode_user.personal_repo_group:
400 % if c.rhodecode_user.personal_repo_group:
399 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
401 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
400 % endif
402 % endif
401 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
403 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
402 ## bookmark-items
404 ## bookmark-items
403 <li class="bookmark-items">
405 <li class="bookmark-items">
404 ${_('Bookmarks')}
406 ${_('Bookmarks')}
405 <div class="pull-right">
407 <div class="pull-right">
406 <a href="${h.route_path('my_account_bookmarks')}">${_('Manage')}</a>
408 <a href="${h.route_path('my_account_bookmarks')}">${_('Manage')}</a>
407 </div>
409 </div>
408 </li>
410 </li>
409 % if not c.bookmark_items:
411 % if not c.bookmark_items:
410 <li>
412 <li>
411 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
413 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
412 </li>
414 </li>
413 % endif
415 % endif
414 % for item in c.bookmark_items:
416 % for item in c.bookmark_items:
415 <li>
417 <li>
416 % if item.repository:
418 % if item.repository:
417 <div>
419 <div>
418 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
420 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
419 <code>${item.position}</code>
421 <code>${item.position}</code>
420 % if item.repository.repo_type == 'hg':
422 % if item.repository.repo_type == 'hg':
421 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
423 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
422 % elif item.repository.repo_type == 'git':
424 % elif item.repository.repo_type == 'git':
423 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
425 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
424 % elif item.repository.repo_type == 'svn':
426 % elif item.repository.repo_type == 'svn':
425 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
427 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
426 % endif
428 % endif
427 ${(item.title or h.shorter(item.repository.repo_name, 30))}
429 ${(item.title or h.shorter(item.repository.repo_name, 30))}
428 </a>
430 </a>
429 </div>
431 </div>
430 % elif item.repository_group:
432 % elif item.repository_group:
431 <div>
433 <div>
432 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
434 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
433 <code>${item.position}</code>
435 <code>${item.position}</code>
434 <i class="icon-folder-close" title="${_('Repository group')}" style="font-size: 16px"></i>
436 <i class="icon-folder-close" title="${_('Repository group')}" style="font-size: 16px"></i>
435 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
437 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
436 </a>
438 </a>
437 </div>
439 </div>
438 % else:
440 % else:
439 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
441 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
440 <code>${item.position}</code>
442 <code>${item.position}</code>
441 ${item.title}
443 ${item.title}
442 </a>
444 </a>
443 % endif
445 % endif
444 </li>
446 </li>
445 % endfor
447 % endfor
446
448
447 <li class="logout">
449 <li class="logout">
448 ${h.secure_form(h.route_path('logout'), request=request)}
450 ${h.secure_form(h.route_path('logout'), request=request)}
449 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
451 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
450 ${h.end_form()}
452 ${h.end_form()}
451 </li>
453 </li>
452 </ol>
454 </ol>
453 </div>
455 </div>
454 %endif
456 %endif
455 </div>
457 </div>
456 </div>
458 </div>
457 ## unread counter
459 ## unread counter
458 <div class="pill_container">
460 <div class="pill_container">
459 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
461 <a class="menu_link_notifications ${'empty' if c.unread_notifications == 0 else ''}" href="${h.route_path('notifications_show_all')}">${c.unread_notifications}</a>
460 </div>
462 </div>
461 % endif
463 % endif
462 </li>
464 </li>
463 </%def>
465 </%def>
464
466
465 <%def name="menu_items(active=None)">
467 <%def name="menu_items(active=None)">
466 <%
468 <%
467 def is_active(selected):
469 def is_active(selected):
468 if selected == active:
470 if selected == active:
469 return "active"
471 return "active"
470 return ""
472 return ""
471 %>
473 %>
472
474
473 <ul id="quick" class="main_nav navigation horizontal-list">
475 <ul id="quick" class="main_nav navigation horizontal-list">
474 ## notice box for important system messages
476 ## notice box for important system messages
475 <li style="display: none">
477 <li style="display: none">
476 <a class="notice-box" href="#openNotice" onclick="showNoticeBox(); return false">
478 <a class="notice-box" href="#openNotice" onclick="showNoticeBox(); return false">
477 <div class="menulabel-notice" >
479 <div class="menulabel-notice" >
478 0
480 0
479 </div>
481 </div>
480 </a>
482 </a>
481 </li>
483 </li>
482
484
483 ## Main filter
485 ## Main filter
484 <li>
486 <li>
485 <div class="menulabel main_filter_box">
487 <div class="menulabel main_filter_box">
486 <div class="main_filter_input_box">
488 <div class="main_filter_input_box">
487 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
489 <input class="main_filter_input" id="main_filter" size="15" type="text" name="main_filter" placeholder="${_('search / go to...')}" value=""/>
488 </div>
490 </div>
489 <div class="main_filter_help_box">
491 <div class="main_filter_help_box">
490 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
492 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
491 </div>
493 </div>
492 </div>
494 </div>
493
495
494 <div id="main_filter_help" style="display: none">
496 <div id="main_filter_help" style="display: none">
495 - Use '/' key to quickly access this field.
497 - Use '/' key to quickly access this field.
496
498
497 - Enter a name of repository, or repository group for quick search.
499 - Enter a name of repository, or repository group for quick search.
498
500
499 - Prefix query to allow special search:
501 - Prefix query to allow special search:
500
502
501 user:admin, to search for usernames
503 user:admin, to search for usernames
502
504
503 user_group:devops, to search for user groups
505 user_group:devops, to search for user groups
504
506
505 commit:efced4, to search for commits
507 commit:efced4, to search for commits
506
508
507 file:models.py, to search for file paths
509 file:models.py, to search for file paths
508 </div>
510 </div>
509 </li>
511 </li>
510
512
511 ## ROOT MENU
513 ## ROOT MENU
512 <li class="${is_active('home')}">
514 <li class="${is_active('home')}">
513 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
515 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
514 <div class="menulabel">${_('Home')}</div>
516 <div class="menulabel">${_('Home')}</div>
515 </a>
517 </a>
516 </li>
518 </li>
517
519
518 %if c.rhodecode_user.username != h.DEFAULT_USER:
520 %if c.rhodecode_user.username != h.DEFAULT_USER:
519 <li class="${is_active('journal')}">
521 <li class="${is_active('journal')}">
520 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
522 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
521 <div class="menulabel">${_('Journal')}</div>
523 <div class="menulabel">${_('Journal')}</div>
522 </a>
524 </a>
523 </li>
525 </li>
524 %else:
526 %else:
525 <li class="${is_active('journal')}">
527 <li class="${is_active('journal')}">
526 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
528 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
527 <div class="menulabel">${_('Public journal')}</div>
529 <div class="menulabel">${_('Public journal')}</div>
528 </a>
530 </a>
529 </li>
531 </li>
530 %endif
532 %endif
531
533
532 <li class="${is_active('gists')}">
534 <li class="${is_active('gists')}">
533 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
535 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
534 <div class="menulabel">${_('Gists')}</div>
536 <div class="menulabel">${_('Gists')}</div>
535 </a>
537 </a>
536 </li>
538 </li>
537
539
538 % if h.HasPermissionAll('hg.admin')('access admin main page'):
540 % if h.HasPermissionAll('hg.admin')('access admin main page'):
539 <li class="${is_active('admin')}">
541 <li class="${is_active('admin')}">
540 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
542 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
541 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
543 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
542 </a>
544 </a>
543 ${admin_menu()}
545 ${admin_menu()}
544 </li>
546 </li>
545 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
547 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
546 <li class="${is_active('admin')}">
548 <li class="${is_active('admin')}">
547 <a class="menulink childs" title="${_('Delegated Admin settings')}">
549 <a class="menulink childs" title="${_('Delegated Admin settings')}">
548 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
550 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
549 </a>
551 </a>
550 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
552 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
551 c.rhodecode_user.repository_groups_admin,
553 c.rhodecode_user.repository_groups_admin,
552 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
554 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
553 </li>
555 </li>
554 % endif
556 % endif
555 ## render extra user menu
557 ## render extra user menu
556 ${usermenu(active=(active=='my_account'))}
558 ${usermenu(active=(active=='my_account'))}
557
559
558 % if c.debug_style:
560 % if c.debug_style:
559 <li>
561 <li>
560 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
562 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
561 <div class="menulabel">${_('[Style]')}</div>
563 <div class="menulabel">${_('[Style]')}</div>
562 </a>
564 </a>
563 </li>
565 </li>
564 % endif
566 % endif
565 </ul>
567 </ul>
566
568
567 <script type="text/javascript">
569 <script type="text/javascript">
568 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
570 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
569
571
570 var formatRepoResult = function(result, container, query, escapeMarkup) {
572 var formatRepoResult = function(result, container, query, escapeMarkup) {
571 return function(data, escapeMarkup) {
573 return function(data, escapeMarkup) {
572 if (!data.repo_id){
574 if (!data.repo_id){
573 return data.text; // optgroup text Repositories
575 return data.text; // optgroup text Repositories
574 }
576 }
575
577
576 var tmpl = '';
578 var tmpl = '';
577 var repoType = data['repo_type'];
579 var repoType = data['repo_type'];
578 var repoName = data['text'];
580 var repoName = data['text'];
579
581
580 if(data && data.type == 'repo'){
582 if(data && data.type == 'repo'){
581 if(repoType === 'hg'){
583 if(repoType === 'hg'){
582 tmpl += '<i class="icon-hg"></i> ';
584 tmpl += '<i class="icon-hg"></i> ';
583 }
585 }
584 else if(repoType === 'git'){
586 else if(repoType === 'git'){
585 tmpl += '<i class="icon-git"></i> ';
587 tmpl += '<i class="icon-git"></i> ';
586 }
588 }
587 else if(repoType === 'svn'){
589 else if(repoType === 'svn'){
588 tmpl += '<i class="icon-svn"></i> ';
590 tmpl += '<i class="icon-svn"></i> ';
589 }
591 }
590 if(data['private']){
592 if(data['private']){
591 tmpl += '<i class="icon-lock" ></i> ';
593 tmpl += '<i class="icon-lock" ></i> ';
592 }
594 }
593 else if(visualShowPublicIcon){
595 else if(visualShowPublicIcon){
594 tmpl += '<i class="icon-unlock-alt"></i> ';
596 tmpl += '<i class="icon-unlock-alt"></i> ';
595 }
597 }
596 }
598 }
597 tmpl += escapeMarkup(repoName);
599 tmpl += escapeMarkup(repoName);
598 return tmpl;
600 return tmpl;
599
601
600 }(result, escapeMarkup);
602 }(result, escapeMarkup);
601 };
603 };
602
604
603 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
605 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
604 return function(data, escapeMarkup) {
606 return function(data, escapeMarkup) {
605 if (!data.repo_group_id){
607 if (!data.repo_group_id){
606 return data.text; // optgroup text Repositories
608 return data.text; // optgroup text Repositories
607 }
609 }
608
610
609 var tmpl = '';
611 var tmpl = '';
610 var repoGroupName = data['text'];
612 var repoGroupName = data['text'];
611
613
612 if(data){
614 if(data){
613
615
614 tmpl += '<i class="icon-folder-close"></i> ';
616 tmpl += '<i class="icon-folder-close"></i> ';
615
617
616 }
618 }
617 tmpl += escapeMarkup(repoGroupName);
619 tmpl += escapeMarkup(repoGroupName);
618 return tmpl;
620 return tmpl;
619
621
620 }(result, escapeMarkup);
622 }(result, escapeMarkup);
621 };
623 };
622
624
623
625
624 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
626 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
625
627
626 if (value.split(':').length === 2) {
628 if (value.split(':').length === 2) {
627 value = value.split(':')[1]
629 value = value.split(':')[1]
628 }
630 }
629
631
630 var searchType = data['type'];
632 var searchType = data['type'];
631 var valueDisplay = data['value_display'];
633 var valueDisplay = data['value_display'];
632
634
633 var escapeRegExChars = function (value) {
635 var escapeRegExChars = function (value) {
634 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
636 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
635 };
637 };
636 var pattern = '(' + escapeRegExChars(value) + ')';
638 var pattern = '(' + escapeRegExChars(value) + ')';
637
639
638 var getRepoIcon = function(repo_type) {
640 var getRepoIcon = function(repo_type) {
639 if (repo_type === 'hg') {
641 if (repo_type === 'hg') {
640 return '<i class="icon-hg"></i> ';
642 return '<i class="icon-hg"></i> ';
641 }
643 }
642 else if (repo_type === 'git') {
644 else if (repo_type === 'git') {
643 return '<i class="icon-git"></i> ';
645 return '<i class="icon-git"></i> ';
644 }
646 }
645 else if (repo_type === 'svn') {
647 else if (repo_type === 'svn') {
646 return '<i class="icon-svn"></i> ';
648 return '<i class="icon-svn"></i> ';
647 }
649 }
648 return ''
650 return ''
649 };
651 };
650
652
651 // highlight match
653 // highlight match
652 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
654 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
653 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
655 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
654
656
655 var icon = '';
657 var icon = '';
656
658
657 if (searchType === 'hint') {
659 if (searchType === 'hint') {
658 icon += '<i class="icon-folder-close"></i> ';
660 icon += '<i class="icon-folder-close"></i> ';
659 }
661 }
660 // full text search
662 // full text search
661 else if (searchType === 'search') {
663 else if (searchType === 'search') {
662 icon += '<i class="icon-more"></i> ';
664 icon += '<i class="icon-more"></i> ';
663 }
665 }
664 // repository
666 // repository
665 else if (searchType === 'repo') {
667 else if (searchType === 'repo') {
666
668
667 var repoIcon = getRepoIcon(data['repo_type']);
669 var repoIcon = getRepoIcon(data['repo_type']);
668 icon += repoIcon;
670 icon += repoIcon;
669
671
670 if (data['private']) {
672 if (data['private']) {
671 icon += '<i class="icon-lock" ></i> ';
673 icon += '<i class="icon-lock" ></i> ';
672 }
674 }
673 else if (visualShowPublicIcon) {
675 else if (visualShowPublicIcon) {
674 icon += '<i class="icon-unlock-alt"></i> ';
676 icon += '<i class="icon-unlock-alt"></i> ';
675 }
677 }
676 }
678 }
677 // repository groups
679 // repository groups
678 else if (searchType === 'repo_group') {
680 else if (searchType === 'repo_group') {
679 icon += '<i class="icon-folder-close"></i> ';
681 icon += '<i class="icon-folder-close"></i> ';
680 }
682 }
681 // user group
683 // user group
682 else if (searchType === 'user_group') {
684 else if (searchType === 'user_group') {
683 icon += '<i class="icon-group"></i> ';
685 icon += '<i class="icon-group"></i> ';
684 }
686 }
685 else if (searchType === 'user') {
687 else if (searchType === 'user') {
686 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
688 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
687 }
689 }
688 // commit
690 // commit
689 else if (searchType === 'commit') {
691 else if (searchType === 'commit') {
690 var repo_data = data['repo_data'];
692 var repo_data = data['repo_data'];
691 var repoIcon = getRepoIcon(repo_data['repository_type']);
693 var repoIcon = getRepoIcon(repo_data['repository_type']);
692 if (repoIcon) {
694 if (repoIcon) {
693 icon += repoIcon;
695 icon += repoIcon;
694 } else {
696 } else {
695 icon += '<i class="icon-tag"></i>';
697 icon += '<i class="icon-tag"></i>';
696 }
698 }
697 }
699 }
698 // file
700 // file
699 else if (searchType === 'file') {
701 else if (searchType === 'file') {
700 var repo_data = data['repo_data'];
702 var repo_data = data['repo_data'];
701 var repoIcon = getRepoIcon(repo_data['repository_type']);
703 var repoIcon = getRepoIcon(repo_data['repository_type']);
702 if (repoIcon) {
704 if (repoIcon) {
703 icon += repoIcon;
705 icon += repoIcon;
704 } else {
706 } else {
705 icon += '<i class="icon-tag"></i>';
707 icon += '<i class="icon-tag"></i>';
706 }
708 }
707 }
709 }
708
710
709 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
711 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
710 return tmpl.format(icon, valueDisplay);
712 return tmpl.format(icon, valueDisplay);
711 };
713 };
712
714
713 var handleSelect = function(element, suggestion) {
715 var handleSelect = function(element, suggestion) {
714 if (suggestion.type === "hint") {
716 if (suggestion.type === "hint") {
715 // we skip action
717 // we skip action
716 $('#main_filter').focus();
718 $('#main_filter').focus();
717 } else {
719 } else {
718 window.location = suggestion['url'];
720 window.location = suggestion['url'];
719 }
721 }
720 };
722 };
721 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
723 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
722 if (queryLowerCase.split(':').length === 2) {
724 if (queryLowerCase.split(':').length === 2) {
723 queryLowerCase = queryLowerCase.split(':')[1]
725 queryLowerCase = queryLowerCase.split(':')[1]
724 }
726 }
725 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
727 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
726 };
728 };
727
729
728 $('#main_filter').autocomplete({
730 $('#main_filter').autocomplete({
729 serviceUrl: pyroutes.url('goto_switcher_data'),
731 serviceUrl: pyroutes.url('goto_switcher_data'),
730 params: {"search_context": templateContext.search_context},
732 params: {"search_context": templateContext.search_context},
731 minChars:2,
733 minChars:2,
732 maxHeight:400,
734 maxHeight:400,
733 deferRequestBy: 300, //miliseconds
735 deferRequestBy: 300, //miliseconds
734 tabDisabled: true,
736 tabDisabled: true,
735 autoSelectFirst: true,
737 autoSelectFirst: true,
736 formatResult: autocompleteMainFilterFormatResult,
738 formatResult: autocompleteMainFilterFormatResult,
737 lookupFilter: autocompleteMainFilterResult,
739 lookupFilter: autocompleteMainFilterResult,
738 onSelect: function (element, suggestion) {
740 onSelect: function (element, suggestion) {
739 handleSelect(element, suggestion);
741 handleSelect(element, suggestion);
740 return false;
742 return false;
741 },
743 },
742 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
744 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
743 if (jqXHR !== 'abort') {
745 if (jqXHR !== 'abort') {
744 alert("Error during search.\nError code: {0}".format(textStatus));
746 alert("Error during search.\nError code: {0}".format(textStatus));
745 window.location = '';
747 window.location = '';
746 }
748 }
747 }
749 }
748 });
750 });
749
751
750 showMainFilterBox = function () {
752 showMainFilterBox = function () {
751 $('#main_filter_help').toggle();
753 $('#main_filter_help').toggle();
752 };
754 };
753
755
754 </script>
756 </script>
755 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
757 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
756 </%def>
758 </%def>
757
759
758 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
760 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
759 <div class="modal-dialog">
761 <div class="modal-dialog">
760 <div class="modal-content">
762 <div class="modal-content">
761 <div class="modal-header">
763 <div class="modal-header">
762 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
764 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
763 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
765 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
764 </div>
766 </div>
765 <div class="modal-body">
767 <div class="modal-body">
766 <div class="block-left">
768 <div class="block-left">
767 <table class="keyboard-mappings">
769 <table class="keyboard-mappings">
768 <tbody>
770 <tbody>
769 <tr>
771 <tr>
770 <th></th>
772 <th></th>
771 <th>${_('Site-wide shortcuts')}</th>
773 <th>${_('Site-wide shortcuts')}</th>
772 </tr>
774 </tr>
773 <%
775 <%
774 elems = [
776 elems = [
775 ('/', 'Use quick search box'),
777 ('/', 'Use quick search box'),
776 ('g h', 'Goto home page'),
778 ('g h', 'Goto home page'),
777 ('g g', 'Goto my private gists page'),
779 ('g g', 'Goto my private gists page'),
778 ('g G', 'Goto my public gists page'),
780 ('g G', 'Goto my public gists page'),
779 ('g 0-9', 'Goto bookmarked items from 0-9'),
781 ('g 0-9', 'Goto bookmarked items from 0-9'),
780 ('n r', 'New repository page'),
782 ('n r', 'New repository page'),
781 ('n g', 'New gist page'),
783 ('n g', 'New gist page'),
782 ]
784 ]
783 %>
785 %>
784 %for key, desc in elems:
786 %for key, desc in elems:
785 <tr>
787 <tr>
786 <td class="keys">
788 <td class="keys">
787 <span class="key tag">${key}</span>
789 <span class="key tag">${key}</span>
788 </td>
790 </td>
789 <td>${desc}</td>
791 <td>${desc}</td>
790 </tr>
792 </tr>
791 %endfor
793 %endfor
792 </tbody>
794 </tbody>
793 </table>
795 </table>
794 </div>
796 </div>
795 <div class="block-left">
797 <div class="block-left">
796 <table class="keyboard-mappings">
798 <table class="keyboard-mappings">
797 <tbody>
799 <tbody>
798 <tr>
800 <tr>
799 <th></th>
801 <th></th>
800 <th>${_('Repositories')}</th>
802 <th>${_('Repositories')}</th>
801 </tr>
803 </tr>
802 <%
804 <%
803 elems = [
805 elems = [
804 ('g s', 'Goto summary page'),
806 ('g s', 'Goto summary page'),
805 ('g c', 'Goto changelog page'),
807 ('g c', 'Goto changelog page'),
806 ('g f', 'Goto files page'),
808 ('g f', 'Goto files page'),
807 ('g F', 'Goto files page with file search activated'),
809 ('g F', 'Goto files page with file search activated'),
808 ('g p', 'Goto pull requests page'),
810 ('g p', 'Goto pull requests page'),
809 ('g o', 'Goto repository settings'),
811 ('g o', 'Goto repository settings'),
810 ('g O', 'Goto repository permissions settings'),
812 ('g O', 'Goto repository permissions settings'),
811 ]
813 ]
812 %>
814 %>
813 %for key, desc in elems:
815 %for key, desc in elems:
814 <tr>
816 <tr>
815 <td class="keys">
817 <td class="keys">
816 <span class="key tag">${key}</span>
818 <span class="key tag">${key}</span>
817 </td>
819 </td>
818 <td>${desc}</td>
820 <td>${desc}</td>
819 </tr>
821 </tr>
820 %endfor
822 %endfor
821 </tbody>
823 </tbody>
822 </table>
824 </table>
823 </div>
825 </div>
824 </div>
826 </div>
825 <div class="modal-footer">
827 <div class="modal-footer">
826 </div>
828 </div>
827 </div><!-- /.modal-content -->
829 </div><!-- /.modal-content -->
828 </div><!-- /.modal-dialog -->
830 </div><!-- /.modal-dialog -->
829 </div><!-- /.modal -->
831 </div><!-- /.modal -->
830
832
@@ -1,104 +1,106 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.mako"/>
2 <%inherit file="base/root.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Sign In')}
5 ${_('Sign In')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <style>body{background-color:#eeeeee;}</style>
11 <style>body{background-color:#eeeeee;}</style>
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 % if c.rhodecode_name:
20 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding">
21 %endif
21 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
22 </div>
23 % endif
22 </div>
24 </div>
23 </div>
25 </div>
24 </div>
26 </div>
25
27
26 <div class="loginwrapper">
28 <div class="loginwrapper">
27 <rhodecode-toast id="notifications"></rhodecode-toast>
29 <rhodecode-toast id="notifications"></rhodecode-toast>
28
30
29 <div class="left-column">
31 <div class="left-column">
30 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
32 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
31 </div>
33 </div>
32
34
33 <%block name="above_login_button" />
35 <%block name="above_login_button" />
34 <div id="login" class="right-column">
36 <div id="login" class="right-column">
35 <!-- login -->
37 <!-- login -->
36 <div class="sign-in-title">
38 <div class="sign-in-title">
37 <h1>${_('Sign In using username/password')}</h1>
39 <h1>${_('Sign In using username/password')}</h1>
38 </div>
40 </div>
39 <div class="inner form">
41 <div class="inner form">
40 ${h.form(request.route_path('login', _query={'came_from': c.came_from}), needs_csrf_token=False)}
42 ${h.form(request.route_path('login', _query={'came_from': c.came_from}), needs_csrf_token=False)}
41
43
42 <label for="username">${_('Username')}:</label>
44 <label for="username">${_('Username')}:</label>
43 ${h.text('username', class_='focus', value=defaults.get('username'))}
45 ${h.text('username', class_='focus', value=defaults.get('username'))}
44 %if 'username' in errors:
46 %if 'username' in errors:
45 <span class="error-message">${errors.get('username')}</span>
47 <span class="error-message">${errors.get('username')}</span>
46 <br />
48 <br />
47 %endif
49 %endif
48
50
49 <label for="password">${_('Password')}:
51 <label for="password">${_('Password')}:
50 %if h.HasPermissionAny('hg.password_reset.enabled')():
52 %if h.HasPermissionAny('hg.password_reset.enabled')():
51 <div class="pull-right">${h.link_to(_('Forgot your password?'), h.route_path('reset_password'), class_='pwd_reset', tabindex="-1")}</div>
53 <div class="pull-right">${h.link_to(_('Forgot your password?'), h.route_path('reset_password'), class_='pwd_reset', tabindex="-1")}</div>
52 %endif
54 %endif
53
55
54 </label>
56 </label>
55 ${h.password('password', class_='focus')}
57 ${h.password('password', class_='focus')}
56 %if 'password' in errors:
58 %if 'password' in errors:
57 <span class="error-message">${errors.get('password')}</span>
59 <span class="error-message">${errors.get('password')}</span>
58 <br />
60 <br />
59 %endif
61 %endif
60
62
61 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
63 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
62 <% timeout = request.registry.settings.get('beaker.session.timeout', '0') %>
64 <% timeout = request.registry.settings.get('beaker.session.timeout', '0') %>
63 % if timeout == '0':
65 % if timeout == '0':
64 <% remember_label = _('Remember my indefinitely') %>
66 <% remember_label = _('Remember my indefinitely') %>
65 % else:
67 % else:
66 <% remember_label = _('Remember me for {}').format(h.age_from_seconds(timeout)) %>
68 <% remember_label = _('Remember me for {}').format(h.age_from_seconds(timeout)) %>
67 % endif
69 % endif
68 <label class="checkbox" for="remember">${remember_label}</label>
70 <label class="checkbox" for="remember">${remember_label}</label>
69
71
70 <p class="links">
72 <p class="links">
71 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
73 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
72 ${h.link_to(_("Create a new account."), request.route_path('register'), class_='new_account')}
74 ${h.link_to(_("Create a new account."), request.route_path('register'), class_='new_account')}
73 %endif
75 %endif
74 </p>
76 </p>
75
77
76 %if not h.HasPermissionAny('hg.password_reset.enabled')():
78 %if not h.HasPermissionAny('hg.password_reset.enabled')():
77 ## password reset hidden or disabled.
79 ## password reset hidden or disabled.
78 <p class="help-block">
80 <p class="help-block">
79 ${_('Password reset is disabled.')} <br/>
81 ${_('Password reset is disabled.')} <br/>
80 ${_('Please contact ')}
82 ${_('Please contact ')}
81 % if c.visual.rhodecode_support_url:
83 % if c.visual.rhodecode_support_url:
82 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
84 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
83 ${_('or')}
85 ${_('or')}
84 % endif
86 % endif
85 ${_('an administrator if you need help.')}
87 ${_('an administrator if you need help.')}
86 </p>
88 </p>
87 %endif
89 %endif
88
90
89 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in", title=_('Sign in to {}').format(c.rhodecode_edition))}
91 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in", title=_('Sign in to {}').format(c.rhodecode_edition))}
90
92
91 ${h.end_form()}
93 ${h.end_form()}
92 <script type="text/javascript">
94 <script type="text/javascript">
93 $(document).ready(function(){
95 $(document).ready(function(){
94 $('#username').focus();
96 $('#username').focus();
95 })
97 })
96 </script>
98 </script>
97
99
98 </div>
100 </div>
99 <!-- end login -->
101 <!-- end login -->
100
102
101 <%block name="below_login_button" />
103 <%block name="below_login_button" />
102 </div>
104 </div>
103 </div>
105 </div>
104 </div>
106 </div>
@@ -1,101 +1,103 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.mako"/>
2 <%inherit file="base/root.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Reset Password')}
5 ${_('Reset Password')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10 <style>body{background-color:#eeeeee;}</style>
10 <style>body{background-color:#eeeeee;}</style>
11
11
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 % if c.rhodecode_name:
20 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding">
21 %endif
21 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
22 </div>
23 % endif
22 </div>
24 </div>
23 </div>
25 </div>
24 </div>
26 </div>
25
27
26 <div class="loginwrapper">
28 <div class="loginwrapper">
27 <rhodecode-toast id="notifications"></rhodecode-toast>
29 <rhodecode-toast id="notifications"></rhodecode-toast>
28 <div class="left-column">
30 <div class="left-column">
29 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
31 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
30 </div>
32 </div>
31
33
32 %if h.HasPermissionAny('hg.password_reset.disabled')():
34 %if h.HasPermissionAny('hg.password_reset.disabled')():
33 <div class="right-column">
35 <div class="right-column">
34 <p>
36 <p>
35 ${_('Password reset is disabled. Please contact ')}
37 ${_('Password reset is disabled. Please contact ')}
36 % if c.visual.rhodecode_support_url:
38 % if c.visual.rhodecode_support_url:
37 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
39 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
38 ${_('or')}
40 ${_('or')}
39 % endif
41 % endif
40 ${_('an administrator if you need help.')}
42 ${_('an administrator if you need help.')}
41 </p>
43 </p>
42 </div>
44 </div>
43 %else:
45 %else:
44 <div id="register" class="right-column">
46 <div id="register" class="right-column">
45 <!-- login -->
47 <!-- login -->
46 <div class="sign-in-title">
48 <div class="sign-in-title">
47 <h1>${_('Reset your Password')}</h1>
49 <h1>${_('Reset your Password')}</h1>
48 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
50 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
49 </div>
51 </div>
50 <div class="inner form">
52 <div class="inner form">
51 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
53 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
52 <label for="email">${_('Email Address')}:</label>
54 <label for="email">${_('Email Address')}:</label>
53 ${h.text('email', defaults.get('email'))}
55 ${h.text('email', defaults.get('email'))}
54 %if 'email' in errors:
56 %if 'email' in errors:
55 <span class="error-message">${errors.get('email')}</span>
57 <span class="error-message">${errors.get('email')}</span>
56 <br />
58 <br />
57 %endif
59 %endif
58 <p class="help-block">${_('Password reset link will be sent to matching email address')}</p>
60 <p class="help-block">${_('Password reset link will be sent to matching email address')}</p>
59
61
60 %if captcha_active:
62 %if captcha_active:
61 <div class="login-captcha">
63 <div class="login-captcha">
62 <label for="email">${_('Captcha')}:</label>
64 <label for="email">${_('Captcha')}:</label>
63 ${h.hidden('recaptcha_field')}
65 ${h.hidden('recaptcha_field')}
64 <div id="recaptcha"></div>
66 <div id="recaptcha"></div>
65
67
66 %if 'recaptcha_field' in errors:
68 %if 'recaptcha_field' in errors:
67 <span class="error-message">${errors.get('recaptcha_field')}</span>
69 <span class="error-message">${errors.get('recaptcha_field')}</span>
68 <br />
70 <br />
69 %endif
71 %endif
70 </div>
72 </div>
71 %endif
73 %endif
72
74
73 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
75 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
74 <p class="help-block pull-right">
76 <p class="help-block pull-right">
75 RhodeCode ${c.rhodecode_edition}
77 RhodeCode ${c.rhodecode_edition}
76 </p>
78 </p>
77
79
78 ${h.end_form()}
80 ${h.end_form()}
79 </div>
81 </div>
80 </div>
82 </div>
81 %endif
83 %endif
82 </div>
84 </div>
83 </div>
85 </div>
84
86
85 <script type="text/javascript">
87 <script type="text/javascript">
86 $(document).ready(function(){
88 $(document).ready(function(){
87 $('#email').focus();
89 $('#email').focus();
88 });
90 });
89 </script>
91 </script>
90
92
91 % if captcha_active:
93 % if captcha_active:
92 <script type="text/javascript">
94 <script type="text/javascript">
93 var onloadCallback = function() {
95 var onloadCallback = function() {
94 grecaptcha.render('recaptcha', {
96 grecaptcha.render('recaptcha', {
95 'sitekey' : "${captcha_public_key}"
97 'sitekey' : "${captcha_public_key}"
96 });
98 });
97 };
99 };
98 </script>
100 </script>
99 <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
101 <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
100 % endif
102 % endif
101
103
@@ -1,146 +1,148 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.mako"/>
2 <%inherit file="base/root.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Create an Account')}
5 ${_('Create an Account')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10 <style>body{background-color:#eeeeee;}</style>
10 <style>body{background-color:#eeeeee;}</style>
11
11
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 % if c.rhodecode_name:
20 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding">
21 %endif
21 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
22 </div>
23 % endif
22 </div>
24 </div>
23 </div>
25 </div>
24 </div>
26 </div>
25
27
26 <div class="loginwrapper">
28 <div class="loginwrapper">
27 <rhodecode-toast id="notifications"></rhodecode-toast>
29 <rhodecode-toast id="notifications"></rhodecode-toast>
28 <div class="left-column">
30 <div class="left-column">
29 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
31 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
30 </div>
32 </div>
31 <%block name="above_register_button" />
33 <%block name="above_register_button" />
32 <div id="register" class="right-column">
34 <div id="register" class="right-column">
33 <!-- login -->
35 <!-- login -->
34 <div class="sign-in-title">
36 <div class="sign-in-title">
35 % if external_auth_provider:
37 % if external_auth_provider:
36 <h1>${_('Create an account linked with {}').format(external_auth_provider)}</h1>
38 <h1>${_('Create an account linked with {}').format(external_auth_provider)}</h1>
37 % else:
39 % else:
38 <h1>${_('Create an account')}</h1>
40 <h1>${_('Create an account')}</h1>
39 % endif
41 % endif
40
42
41 <h4>${h.link_to(_("Go to the login page to sign in with an existing account."), request.route_path('login'))}</h4>
43 <h4>${h.link_to(_("Go to the login page to sign in with an existing account."), request.route_path('login'))}</h4>
42 </div>
44 </div>
43 <div class="inner form">
45 <div class="inner form">
44 ${h.form(request.route_path('register'), needs_csrf_token=False)}
46 ${h.form(request.route_path('register'), needs_csrf_token=False)}
45
47
46 <label for="username">${_('Username')}:</label>
48 <label for="username">${_('Username')}:</label>
47 ${h.text('username', defaults.get('username'))}
49 ${h.text('username', defaults.get('username'))}
48 %if 'username' in errors:
50 %if 'username' in errors:
49 <span class="error-message">${errors.get('username')}</span>
51 <span class="error-message">${errors.get('username')}</span>
50 <br />
52 <br />
51 %endif
53 %endif
52
54
53 % if external_auth_provider:
55 % if external_auth_provider:
54 ## store internal marker about external identity
56 ## store internal marker about external identity
55 ${h.hidden('external_identity', external_auth_provider)}
57 ${h.hidden('external_identity', external_auth_provider)}
56 ## hide password prompts for social auth
58 ## hide password prompts for social auth
57 <div style="display: none">
59 <div style="display: none">
58 % endif
60 % endif
59
61
60 <label for="password">${_('Password')}:</label>
62 <label for="password">${_('Password')}:</label>
61 ${h.password('password', defaults.get('password'))}
63 ${h.password('password', defaults.get('password'))}
62 %if 'password' in errors:
64 %if 'password' in errors:
63 <span class="error-message">${errors.get('password')}</span>
65 <span class="error-message">${errors.get('password')}</span>
64 <br />
66 <br />
65 %endif
67 %endif
66
68
67 <label for="password_confirmation">${_('Re-enter password')}:</label>
69 <label for="password_confirmation">${_('Re-enter password')}:</label>
68 ${h.password('password_confirmation', defaults.get('password_confirmation'))}
70 ${h.password('password_confirmation', defaults.get('password_confirmation'))}
69 %if 'password_confirmation' in errors:
71 %if 'password_confirmation' in errors:
70 <span class="error-message">${errors.get('password_confirmation')}</span>
72 <span class="error-message">${errors.get('password_confirmation')}</span>
71 <br />
73 <br />
72 %endif
74 %endif
73
75
74 % if external_auth_provider:
76 % if external_auth_provider:
75 ## hide password prompts for social auth
77 ## hide password prompts for social auth
76 </div>
78 </div>
77 % endif
79 % endif
78
80
79 <label for="firstname">${_('First Name')}:</label>
81 <label for="firstname">${_('First Name')}:</label>
80 ${h.text('firstname', defaults.get('firstname'))}
82 ${h.text('firstname', defaults.get('firstname'))}
81 %if 'firstname' in errors:
83 %if 'firstname' in errors:
82 <span class="error-message">${errors.get('firstname')}</span>
84 <span class="error-message">${errors.get('firstname')}</span>
83 <br />
85 <br />
84 %endif
86 %endif
85
87
86 <label for="lastname">${_('Last Name')}:</label>
88 <label for="lastname">${_('Last Name')}:</label>
87 ${h.text('lastname', defaults.get('lastname'))}
89 ${h.text('lastname', defaults.get('lastname'))}
88 %if 'lastname' in errors:
90 %if 'lastname' in errors:
89 <span class="error-message">${errors.get('lastname')}</span>
91 <span class="error-message">${errors.get('lastname')}</span>
90 <br />
92 <br />
91 %endif
93 %endif
92
94
93 <label for="email">${_('Email')}:</label>
95 <label for="email">${_('Email')}:</label>
94 ${h.text('email', defaults.get('email'))}
96 ${h.text('email', defaults.get('email'))}
95 %if 'email' in errors:
97 %if 'email' in errors:
96 <span class="error-message">${errors.get('email')}</span>
98 <span class="error-message">${errors.get('email')}</span>
97 <br />
99 <br />
98 %endif
100 %endif
99
101
100 %if captcha_active:
102 %if captcha_active:
101 <div>
103 <div>
102 <label for="recaptcha">${_('Captcha')}:</label>
104 <label for="recaptcha">${_('Captcha')}:</label>
103 ${h.hidden('recaptcha_field')}
105 ${h.hidden('recaptcha_field')}
104 <div id="recaptcha"></div>
106 <div id="recaptcha"></div>
105 %if 'recaptcha_field' in errors:
107 %if 'recaptcha_field' in errors:
106 <span class="error-message">${errors.get('recaptcha_field')}</span>
108 <span class="error-message">${errors.get('recaptcha_field')}</span>
107 <br />
109 <br />
108 %endif
110 %endif
109 </div>
111 </div>
110 %endif
112 %endif
111
113
112 %if not auto_active:
114 %if not auto_active:
113 <p class="activation_msg">
115 <p class="activation_msg">
114 ${_('Account activation requires admin approval.')}
116 ${_('Account activation requires admin approval.')}
115 </p>
117 </p>
116 %endif
118 %endif
117 <p class="register_message">
119 <p class="register_message">
118 ${register_message|n}
120 ${register_message|n}
119 </p>
121 </p>
120
122
121 ${h.submit('sign_up',_('Create Account'), class_="btn sign-in", title=_('Create Account in {}').format(c.rhodecode_edition))}
123 ${h.submit('sign_up',_('Create Account'), class_="btn sign-in", title=_('Create Account in {}').format(c.rhodecode_edition))}
122 ${h.end_form()}
124 ${h.end_form()}
123 </div>
125 </div>
124 <%block name="below_register_button" />
126 <%block name="below_register_button" />
125 </div>
127 </div>
126 </div>
128 </div>
127 </div>
129 </div>
128
130
129
131
130 <script type="text/javascript">
132 <script type="text/javascript">
131 $(document).ready(function(){
133 $(document).ready(function(){
132 $('#username').focus();
134 $('#username').focus();
133 });
135 });
134 </script>
136 </script>
135
137
136 % if captcha_active:
138 % if captcha_active:
137 <script type="text/javascript">
139 <script type="text/javascript">
138 var onloadCallback = function() {
140 var onloadCallback = function() {
139 grecaptcha.render('recaptcha', {
141 grecaptcha.render('recaptcha', {
140 'sitekey' : "${captcha_public_key}"
142 'sitekey' : "${captcha_public_key}"
141 });
143 });
142 };
144 };
143 </script>
145 </script>
144 <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
146 <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
145 % endif
147 % endif
146
148
General Comments 0
You need to be logged in to leave comments. Login now