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