##// END OF EJS Templates
commit-ranges: enable combined diff compare directly from range selector.
milka -
r4552:a0029748 default
parent child Browse files
Show More
@@ -1,802 +1,816 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 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 logging
22 22 import collections
23 23
24 24 from pyramid.httpexceptions import (
25 25 HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden, HTTPConflict)
26 26 from pyramid.view import view_config
27 27 from pyramid.renderers import render
28 28 from pyramid.response import Response
29 29
30 30 from rhodecode.apps._base import RepoAppView
31 31 from rhodecode.apps.file_store import utils as store_utils
32 32 from rhodecode.apps.file_store.exceptions import FileNotAllowedException, FileOverSizeException
33 33
34 34 from rhodecode.lib import diffs, codeblocks, channelstream
35 35 from rhodecode.lib.auth import (
36 36 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired)
37 37 from rhodecode.lib.ext_json import json
38 38 from rhodecode.lib.compat import OrderedDict
39 39 from rhodecode.lib.diffs import (
40 40 cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
41 41 get_diff_whitespace_flag)
42 42 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError, CommentVersionMismatch
43 43 import rhodecode.lib.helpers as h
44 44 from rhodecode.lib.utils2 import safe_unicode, str2bool, StrictAttributeDict
45 45 from rhodecode.lib.vcs.backends.base import EmptyCommit
46 46 from rhodecode.lib.vcs.exceptions import (
47 47 RepositoryError, CommitDoesNotExistError)
48 48 from rhodecode.model.db import ChangesetComment, ChangesetStatus, FileStore, \
49 49 ChangesetCommentHistory
50 50 from rhodecode.model.changeset_status import ChangesetStatusModel
51 51 from rhodecode.model.comment import CommentsModel
52 52 from rhodecode.model.meta import Session
53 53 from rhodecode.model.settings import VcsSettingsModel
54 54
55 55 log = logging.getLogger(__name__)
56 56
57 57
58 58 def _update_with_GET(params, request):
59 59 for k in ['diff1', 'diff2', 'diff']:
60 60 params[k] += request.GET.getall(k)
61 61
62 62
63 63 class RepoCommitsView(RepoAppView):
64 64 def load_default_context(self):
65 65 c = self._get_local_tmpl_context(include_app_defaults=True)
66 66 c.rhodecode_repo = self.rhodecode_vcs_repo
67 67
68 68 return c
69 69
70 70 def _is_diff_cache_enabled(self, target_repo):
71 71 caching_enabled = self._get_general_setting(
72 72 target_repo, 'rhodecode_diff_cache')
73 73 log.debug('Diff caching enabled: %s', caching_enabled)
74 74 return caching_enabled
75 75
76 76 def _commit(self, commit_id_range, method):
77 77 _ = self.request.translate
78 78 c = self.load_default_context()
79 79 c.fulldiff = self.request.GET.get('fulldiff')
80 redirect_to_combined = str2bool(self.request.GET.get('redirect_combined'))
80 81
81 82 # fetch global flags of ignore ws or context lines
82 83 diff_context = get_diff_context(self.request)
83 84 hide_whitespace_changes = get_diff_whitespace_flag(self.request)
84 85
85 86 # diff_limit will cut off the whole diff if the limit is applied
86 87 # otherwise it will just hide the big files from the front-end
87 88 diff_limit = c.visual.cut_off_limit_diff
88 89 file_limit = c.visual.cut_off_limit_file
89 90
90 91 # get ranges of commit ids if preset
91 92 commit_range = commit_id_range.split('...')[:2]
92 93
93 94 try:
94 95 pre_load = ['affected_files', 'author', 'branch', 'date',
95 96 'message', 'parents']
96 97 if self.rhodecode_vcs_repo.alias == 'hg':
97 98 pre_load += ['hidden', 'obsolete', 'phase']
98 99
99 100 if len(commit_range) == 2:
100 101 commits = self.rhodecode_vcs_repo.get_commits(
101 102 start_id=commit_range[0], end_id=commit_range[1],
102 103 pre_load=pre_load, translate_tags=False)
103 104 commits = list(commits)
104 105 else:
105 106 commits = [self.rhodecode_vcs_repo.get_commit(
106 107 commit_id=commit_id_range, pre_load=pre_load)]
107 108
108 109 c.commit_ranges = commits
109 110 if not c.commit_ranges:
110 111 raise RepositoryError('The commit range returned an empty result')
111 112 except CommitDoesNotExistError as e:
112 113 msg = _('No such commit exists. Org exception: `{}`').format(e)
113 114 h.flash(msg, category='error')
114 115 raise HTTPNotFound()
115 116 except Exception:
116 117 log.exception("General failure")
117 118 raise HTTPNotFound()
118 119 single_commit = len(c.commit_ranges) == 1
119 120
121 if redirect_to_combined and not single_commit:
122 source_ref = getattr(c.commit_ranges[0].parents[0]
123 if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id')
124 target_ref = c.commit_ranges[-1].raw_id
125 next_url = h.route_path(
126 'repo_compare',
127 repo_name=c.repo_name,
128 source_ref_type='rev',
129 source_ref=source_ref,
130 target_ref_type='rev',
131 target_ref=target_ref)
132 raise HTTPFound(next_url)
133
120 134 c.changes = OrderedDict()
121 135 c.lines_added = 0
122 136 c.lines_deleted = 0
123 137
124 138 # auto collapse if we have more than limit
125 139 collapse_limit = diffs.DiffProcessor._collapse_commits_over
126 140 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
127 141
128 142 c.commit_statuses = ChangesetStatus.STATUSES
129 143 c.inline_comments = []
130 144 c.files = []
131 145
132 146 c.comments = []
133 147 c.unresolved_comments = []
134 148 c.resolved_comments = []
135 149
136 150 # Single commit
137 151 if single_commit:
138 152 commit = c.commit_ranges[0]
139 153 c.comments = CommentsModel().get_comments(
140 154 self.db_repo.repo_id,
141 155 revision=commit.raw_id)
142 156
143 157 # comments from PR
144 158 statuses = ChangesetStatusModel().get_statuses(
145 159 self.db_repo.repo_id, commit.raw_id,
146 160 with_revisions=True)
147 161
148 162 prs = set()
149 163 reviewers = list()
150 164 reviewers_duplicates = set() # to not have duplicates from multiple votes
151 165 for c_status in statuses:
152 166
153 167 # extract associated pull-requests from votes
154 168 if c_status.pull_request:
155 169 prs.add(c_status.pull_request)
156 170
157 171 # extract reviewers
158 172 _user_id = c_status.author.user_id
159 173 if _user_id not in reviewers_duplicates:
160 174 reviewers.append(
161 175 StrictAttributeDict({
162 176 'user': c_status.author,
163 177
164 178 # fake attributed for commit, page that we don't have
165 179 # but we share the display with PR page
166 180 'mandatory': False,
167 181 'reasons': [],
168 182 'rule_user_group_data': lambda: None
169 183 })
170 184 )
171 185 reviewers_duplicates.add(_user_id)
172 186
173 187 c.reviewers_count = len(reviewers)
174 188 c.observers_count = 0
175 189
176 190 # from associated statuses, check the pull requests, and
177 191 # show comments from them
178 192 for pr in prs:
179 193 c.comments.extend(pr.comments)
180 194
181 195 c.unresolved_comments = CommentsModel()\
182 196 .get_commit_unresolved_todos(commit.raw_id)
183 197 c.resolved_comments = CommentsModel()\
184 198 .get_commit_resolved_todos(commit.raw_id)
185 199
186 200 c.inline_comments_flat = CommentsModel()\
187 201 .get_commit_inline_comments(commit.raw_id)
188 202
189 203 review_statuses = ChangesetStatusModel().aggregate_votes_by_user(
190 204 statuses, reviewers)
191 205
192 206 c.commit_review_status = ChangesetStatus.STATUS_NOT_REVIEWED
193 207
194 208 c.commit_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
195 209
196 210 for review_obj, member, reasons, mandatory, status in review_statuses:
197 211 member_reviewer = h.reviewer_as_json(
198 212 member, reasons=reasons, mandatory=mandatory, role=None,
199 213 user_group=None
200 214 )
201 215
202 216 current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED
203 217 member_reviewer['review_status'] = current_review_status
204 218 member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status)
205 219 member_reviewer['allowed_to_update'] = False
206 220 c.commit_set_reviewers_data_json['reviewers'].append(member_reviewer)
207 221
208 222 c.commit_set_reviewers_data_json = json.dumps(c.commit_set_reviewers_data_json)
209 223
210 224 # NOTE(marcink): this uses the same voting logic as in pull-requests
211 225 c.commit_review_status = ChangesetStatusModel().calculate_status(review_statuses)
212 226 c.commit_broadcast_channel = channelstream.comment_channel(c.repo_name, commit_obj=commit)
213 227
214 228 diff = None
215 229 # Iterate over ranges (default commit view is always one commit)
216 230 for commit in c.commit_ranges:
217 231 c.changes[commit.raw_id] = []
218 232
219 233 commit2 = commit
220 234 commit1 = commit.first_parent
221 235
222 236 if method == 'show':
223 237 inline_comments = CommentsModel().get_inline_comments(
224 238 self.db_repo.repo_id, revision=commit.raw_id)
225 239 c.inline_cnt = len(CommentsModel().get_inline_comments_as_list(
226 240 inline_comments))
227 241 c.inline_comments = inline_comments
228 242
229 243 cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(
230 244 self.db_repo)
231 245 cache_file_path = diff_cache_exist(
232 246 cache_path, 'diff', commit.raw_id,
233 247 hide_whitespace_changes, diff_context, c.fulldiff)
234 248
235 249 caching_enabled = self._is_diff_cache_enabled(self.db_repo)
236 250 force_recache = str2bool(self.request.GET.get('force_recache'))
237 251
238 252 cached_diff = None
239 253 if caching_enabled:
240 254 cached_diff = load_cached_diff(cache_file_path)
241 255
242 256 has_proper_diff_cache = cached_diff and cached_diff.get('diff')
243 257 if not force_recache and has_proper_diff_cache:
244 258 diffset = cached_diff['diff']
245 259 else:
246 260 vcs_diff = self.rhodecode_vcs_repo.get_diff(
247 261 commit1, commit2,
248 262 ignore_whitespace=hide_whitespace_changes,
249 263 context=diff_context)
250 264
251 265 diff_processor = diffs.DiffProcessor(
252 266 vcs_diff, format='newdiff', diff_limit=diff_limit,
253 267 file_limit=file_limit, show_full_diff=c.fulldiff)
254 268
255 269 _parsed = diff_processor.prepare()
256 270
257 271 diffset = codeblocks.DiffSet(
258 272 repo_name=self.db_repo_name,
259 273 source_node_getter=codeblocks.diffset_node_getter(commit1),
260 274 target_node_getter=codeblocks.diffset_node_getter(commit2))
261 275
262 276 diffset = self.path_filter.render_patchset_filtered(
263 277 diffset, _parsed, commit1.raw_id, commit2.raw_id)
264 278
265 279 # save cached diff
266 280 if caching_enabled:
267 281 cache_diff(cache_file_path, diffset, None)
268 282
269 283 c.limited_diff = diffset.limited_diff
270 284 c.changes[commit.raw_id] = diffset
271 285 else:
272 286 # TODO(marcink): no cache usage here...
273 287 _diff = self.rhodecode_vcs_repo.get_diff(
274 288 commit1, commit2,
275 289 ignore_whitespace=hide_whitespace_changes, context=diff_context)
276 290 diff_processor = diffs.DiffProcessor(
277 291 _diff, format='newdiff', diff_limit=diff_limit,
278 292 file_limit=file_limit, show_full_diff=c.fulldiff)
279 293 # downloads/raw we only need RAW diff nothing else
280 294 diff = self.path_filter.get_raw_patch(diff_processor)
281 295 c.changes[commit.raw_id] = [None, None, None, None, diff, None, None]
282 296
283 297 # sort comments by how they were generated
284 298 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
285 299 c.at_version_num = None
286 300
287 301 if len(c.commit_ranges) == 1:
288 302 c.commit = c.commit_ranges[0]
289 303 c.parent_tmpl = ''.join(
290 304 '# Parent %s\n' % x.raw_id for x in c.commit.parents)
291 305
292 306 if method == 'download':
293 307 response = Response(diff)
294 308 response.content_type = 'text/plain'
295 309 response.content_disposition = (
296 310 'attachment; filename=%s.diff' % commit_id_range[:12])
297 311 return response
298 312 elif method == 'patch':
299 313 c.diff = safe_unicode(diff)
300 314 patch = render(
301 315 'rhodecode:templates/changeset/patch_changeset.mako',
302 316 self._get_template_context(c), self.request)
303 317 response = Response(patch)
304 318 response.content_type = 'text/plain'
305 319 return response
306 320 elif method == 'raw':
307 321 response = Response(diff)
308 322 response.content_type = 'text/plain'
309 323 return response
310 324 elif method == 'show':
311 325 if len(c.commit_ranges) == 1:
312 326 html = render(
313 327 'rhodecode:templates/changeset/changeset.mako',
314 328 self._get_template_context(c), self.request)
315 329 return Response(html)
316 330 else:
317 331 c.ancestor = None
318 332 c.target_repo = self.db_repo
319 333 html = render(
320 334 'rhodecode:templates/changeset/changeset_range.mako',
321 335 self._get_template_context(c), self.request)
322 336 return Response(html)
323 337
324 338 raise HTTPBadRequest()
325 339
326 340 @LoginRequired()
327 341 @HasRepoPermissionAnyDecorator(
328 342 'repository.read', 'repository.write', 'repository.admin')
329 343 @view_config(
330 344 route_name='repo_commit', request_method='GET',
331 345 renderer=None)
332 346 def repo_commit_show(self):
333 347 commit_id = self.request.matchdict['commit_id']
334 348 return self._commit(commit_id, method='show')
335 349
336 350 @LoginRequired()
337 351 @HasRepoPermissionAnyDecorator(
338 352 'repository.read', 'repository.write', 'repository.admin')
339 353 @view_config(
340 354 route_name='repo_commit_raw', request_method='GET',
341 355 renderer=None)
342 356 @view_config(
343 357 route_name='repo_commit_raw_deprecated', request_method='GET',
344 358 renderer=None)
345 359 def repo_commit_raw(self):
346 360 commit_id = self.request.matchdict['commit_id']
347 361 return self._commit(commit_id, method='raw')
348 362
349 363 @LoginRequired()
350 364 @HasRepoPermissionAnyDecorator(
351 365 'repository.read', 'repository.write', 'repository.admin')
352 366 @view_config(
353 367 route_name='repo_commit_patch', request_method='GET',
354 368 renderer=None)
355 369 def repo_commit_patch(self):
356 370 commit_id = self.request.matchdict['commit_id']
357 371 return self._commit(commit_id, method='patch')
358 372
359 373 @LoginRequired()
360 374 @HasRepoPermissionAnyDecorator(
361 375 'repository.read', 'repository.write', 'repository.admin')
362 376 @view_config(
363 377 route_name='repo_commit_download', request_method='GET',
364 378 renderer=None)
365 379 def repo_commit_download(self):
366 380 commit_id = self.request.matchdict['commit_id']
367 381 return self._commit(commit_id, method='download')
368 382
369 383 @LoginRequired()
370 384 @NotAnonymous()
371 385 @HasRepoPermissionAnyDecorator(
372 386 'repository.read', 'repository.write', 'repository.admin')
373 387 @CSRFRequired()
374 388 @view_config(
375 389 route_name='repo_commit_comment_create', request_method='POST',
376 390 renderer='json_ext')
377 391 def repo_commit_comment_create(self):
378 392 _ = self.request.translate
379 393 commit_id = self.request.matchdict['commit_id']
380 394
381 395 c = self.load_default_context()
382 396 status = self.request.POST.get('changeset_status', None)
383 397 is_draft = str2bool(self.request.POST.get('draft'))
384 398 text = self.request.POST.get('text')
385 399 comment_type = self.request.POST.get('comment_type')
386 400 resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
387 401 f_path = self.request.POST.get('f_path')
388 402 line_no = self.request.POST.get('line')
389 403 target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path)))
390 404
391 405 if status:
392 406 text = text or (_('Status change %(transition_icon)s %(status)s')
393 407 % {'transition_icon': '>',
394 408 'status': ChangesetStatus.get_status_lbl(status)})
395 409
396 410 multi_commit_ids = []
397 411 for _commit_id in self.request.POST.get('commit_ids', '').split(','):
398 412 if _commit_id not in ['', None, EmptyCommit.raw_id]:
399 413 if _commit_id not in multi_commit_ids:
400 414 multi_commit_ids.append(_commit_id)
401 415
402 416 commit_ids = multi_commit_ids or [commit_id]
403 417
404 418 data = {}
405 419 # Multiple comments for each passed commit id
406 420 for current_id in filter(None, commit_ids):
407 421 comment = CommentsModel().create(
408 422 text=text,
409 423 repo=self.db_repo.repo_id,
410 424 user=self._rhodecode_db_user.user_id,
411 425 commit_id=current_id,
412 426 f_path=f_path,
413 427 line_no=line_no,
414 428 status_change=(ChangesetStatus.get_status_lbl(status)
415 429 if status else None),
416 430 status_change_type=status,
417 431 comment_type=comment_type,
418 432 is_draft=is_draft,
419 433 resolves_comment_id=resolves_comment_id,
420 434 auth_user=self._rhodecode_user,
421 435 send_email=not is_draft, # skip notification for draft comments
422 436 )
423 437 is_inline = comment.is_inline
424 438
425 439 # get status if set !
426 440 if status:
427 441 # if latest status was from pull request and it's closed
428 442 # disallow changing status !
429 443 # dont_allow_on_closed_pull_request = True !
430 444
431 445 try:
432 446 ChangesetStatusModel().set_status(
433 447 self.db_repo.repo_id,
434 448 status,
435 449 self._rhodecode_db_user.user_id,
436 450 comment,
437 451 revision=current_id,
438 452 dont_allow_on_closed_pull_request=True
439 453 )
440 454 except StatusChangeOnClosedPullRequestError:
441 455 msg = _('Changing the status of a commit associated with '
442 456 'a closed pull request is not allowed')
443 457 log.exception(msg)
444 458 h.flash(msg, category='warning')
445 459 raise HTTPFound(h.route_path(
446 460 'repo_commit', repo_name=self.db_repo_name,
447 461 commit_id=current_id))
448 462
449 463 # skip notifications for drafts
450 464 if not is_draft:
451 465 commit = self.db_repo.get_commit(current_id)
452 466 CommentsModel().trigger_commit_comment_hook(
453 467 self.db_repo, self._rhodecode_user, 'create',
454 468 data={'comment': comment, 'commit': commit})
455 469
456 470 comment_id = comment.comment_id
457 471 data[comment_id] = {
458 472 'target_id': target_elem_id
459 473 }
460 474 c.co = comment
461 475 c.at_version_num = 0
462 476 c.is_new = True
463 477 rendered_comment = render(
464 478 'rhodecode:templates/changeset/changeset_comment_block.mako',
465 479 self._get_template_context(c), self.request)
466 480
467 481 data[comment_id].update(comment.get_dict())
468 482 data[comment_id].update({'rendered_text': rendered_comment})
469 483
470 484 # skip channelstream for draft comments
471 485 if not is_draft:
472 486 comment_broadcast_channel = channelstream.comment_channel(
473 487 self.db_repo_name, commit_obj=commit)
474 488
475 489 comment_data = data
476 490 posted_comment_type = 'inline' if is_inline else 'general'
477 491 channelstream.comment_channelstream_push(
478 492 self.request, comment_broadcast_channel, self._rhodecode_user,
479 493 _('posted a new {} comment').format(posted_comment_type),
480 494 comment_data=comment_data)
481 495
482 496 # finalize, commit and redirect
483 497 Session().commit()
484 498
485 499 return data
486 500
487 501 @LoginRequired()
488 502 @NotAnonymous()
489 503 @HasRepoPermissionAnyDecorator(
490 504 'repository.read', 'repository.write', 'repository.admin')
491 505 @CSRFRequired()
492 506 @view_config(
493 507 route_name='repo_commit_comment_preview', request_method='POST',
494 508 renderer='string', xhr=True)
495 509 def repo_commit_comment_preview(self):
496 510 # Technically a CSRF token is not needed as no state changes with this
497 511 # call. However, as this is a POST is better to have it, so automated
498 512 # tools don't flag it as potential CSRF.
499 513 # Post is required because the payload could be bigger than the maximum
500 514 # allowed by GET.
501 515
502 516 text = self.request.POST.get('text')
503 517 renderer = self.request.POST.get('renderer') or 'rst'
504 518 if text:
505 519 return h.render(text, renderer=renderer, mentions=True,
506 520 repo_name=self.db_repo_name)
507 521 return ''
508 522
509 523 @LoginRequired()
510 524 @HasRepoPermissionAnyDecorator(
511 525 'repository.read', 'repository.write', 'repository.admin')
512 526 @CSRFRequired()
513 527 @view_config(
514 528 route_name='repo_commit_comment_history_view', request_method='POST',
515 529 renderer='string', xhr=True)
516 530 def repo_commit_comment_history_view(self):
517 531 c = self.load_default_context()
518 532
519 533 comment_history_id = self.request.matchdict['comment_history_id']
520 534 comment_history = ChangesetCommentHistory.get_or_404(comment_history_id)
521 535 is_repo_comment = comment_history.comment.repo.repo_id == self.db_repo.repo_id
522 536
523 537 if is_repo_comment:
524 538 c.comment_history = comment_history
525 539
526 540 rendered_comment = render(
527 541 'rhodecode:templates/changeset/comment_history.mako',
528 542 self._get_template_context(c)
529 543 , self.request)
530 544 return rendered_comment
531 545 else:
532 546 log.warning('No permissions for user %s to show comment_history_id: %s',
533 547 self._rhodecode_db_user, comment_history_id)
534 548 raise HTTPNotFound()
535 549
536 550 @LoginRequired()
537 551 @NotAnonymous()
538 552 @HasRepoPermissionAnyDecorator(
539 553 'repository.read', 'repository.write', 'repository.admin')
540 554 @CSRFRequired()
541 555 @view_config(
542 556 route_name='repo_commit_comment_attachment_upload', request_method='POST',
543 557 renderer='json_ext', xhr=True)
544 558 def repo_commit_comment_attachment_upload(self):
545 559 c = self.load_default_context()
546 560 upload_key = 'attachment'
547 561
548 562 file_obj = self.request.POST.get(upload_key)
549 563
550 564 if file_obj is None:
551 565 self.request.response.status = 400
552 566 return {'store_fid': None,
553 567 'access_path': None,
554 568 'error': '{} data field is missing'.format(upload_key)}
555 569
556 570 if not hasattr(file_obj, 'filename'):
557 571 self.request.response.status = 400
558 572 return {'store_fid': None,
559 573 'access_path': None,
560 574 'error': 'filename cannot be read from the data field'}
561 575
562 576 filename = file_obj.filename
563 577 file_display_name = filename
564 578
565 579 metadata = {
566 580 'user_uploaded': {'username': self._rhodecode_user.username,
567 581 'user_id': self._rhodecode_user.user_id,
568 582 'ip': self._rhodecode_user.ip_addr}}
569 583
570 584 # TODO(marcink): allow .ini configuration for allowed_extensions, and file-size
571 585 allowed_extensions = [
572 586 'gif', '.jpeg', '.jpg', '.png', '.docx', '.gz', '.log', '.pdf',
573 587 '.pptx', '.txt', '.xlsx', '.zip']
574 588 max_file_size = 10 * 1024 * 1024 # 10MB, also validated via dropzone.js
575 589
576 590 try:
577 591 storage = store_utils.get_file_storage(self.request.registry.settings)
578 592 store_uid, metadata = storage.save_file(
579 593 file_obj.file, filename, extra_metadata=metadata,
580 594 extensions=allowed_extensions, max_filesize=max_file_size)
581 595 except FileNotAllowedException:
582 596 self.request.response.status = 400
583 597 permitted_extensions = ', '.join(allowed_extensions)
584 598 error_msg = 'File `{}` is not allowed. ' \
585 599 'Only following extensions are permitted: {}'.format(
586 600 filename, permitted_extensions)
587 601 return {'store_fid': None,
588 602 'access_path': None,
589 603 'error': error_msg}
590 604 except FileOverSizeException:
591 605 self.request.response.status = 400
592 606 limit_mb = h.format_byte_size_binary(max_file_size)
593 607 return {'store_fid': None,
594 608 'access_path': None,
595 609 'error': 'File {} is exceeding allowed limit of {}.'.format(
596 610 filename, limit_mb)}
597 611
598 612 try:
599 613 entry = FileStore.create(
600 614 file_uid=store_uid, filename=metadata["filename"],
601 615 file_hash=metadata["sha256"], file_size=metadata["size"],
602 616 file_display_name=file_display_name,
603 617 file_description=u'comment attachment `{}`'.format(safe_unicode(filename)),
604 618 hidden=True, check_acl=True, user_id=self._rhodecode_user.user_id,
605 619 scope_repo_id=self.db_repo.repo_id
606 620 )
607 621 Session().add(entry)
608 622 Session().commit()
609 623 log.debug('Stored upload in DB as %s', entry)
610 624 except Exception:
611 625 log.exception('Failed to store file %s', filename)
612 626 self.request.response.status = 400
613 627 return {'store_fid': None,
614 628 'access_path': None,
615 629 'error': 'File {} failed to store in DB.'.format(filename)}
616 630
617 631 Session().commit()
618 632
619 633 return {
620 634 'store_fid': store_uid,
621 635 'access_path': h.route_path(
622 636 'download_file', fid=store_uid),
623 637 'fqn_access_path': h.route_url(
624 638 'download_file', fid=store_uid),
625 639 'repo_access_path': h.route_path(
626 640 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
627 641 'repo_fqn_access_path': h.route_url(
628 642 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
629 643 }
630 644
631 645 @LoginRequired()
632 646 @NotAnonymous()
633 647 @HasRepoPermissionAnyDecorator(
634 648 'repository.read', 'repository.write', 'repository.admin')
635 649 @CSRFRequired()
636 650 @view_config(
637 651 route_name='repo_commit_comment_delete', request_method='POST',
638 652 renderer='json_ext')
639 653 def repo_commit_comment_delete(self):
640 654 commit_id = self.request.matchdict['commit_id']
641 655 comment_id = self.request.matchdict['comment_id']
642 656
643 657 comment = ChangesetComment.get_or_404(comment_id)
644 658 if not comment:
645 659 log.debug('Comment with id:%s not found, skipping', comment_id)
646 660 # comment already deleted in another call probably
647 661 return True
648 662
649 663 if comment.immutable:
650 664 # don't allow deleting comments that are immutable
651 665 raise HTTPForbidden()
652 666
653 667 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
654 668 super_admin = h.HasPermissionAny('hg.admin')()
655 669 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
656 670 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
657 671 comment_repo_admin = is_repo_admin and is_repo_comment
658 672
659 673 if super_admin or comment_owner or comment_repo_admin:
660 674 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
661 675 Session().commit()
662 676 return True
663 677 else:
664 678 log.warning('No permissions for user %s to delete comment_id: %s',
665 679 self._rhodecode_db_user, comment_id)
666 680 raise HTTPNotFound()
667 681
668 682 @LoginRequired()
669 683 @NotAnonymous()
670 684 @HasRepoPermissionAnyDecorator(
671 685 'repository.read', 'repository.write', 'repository.admin')
672 686 @CSRFRequired()
673 687 @view_config(
674 688 route_name='repo_commit_comment_edit', request_method='POST',
675 689 renderer='json_ext')
676 690 def repo_commit_comment_edit(self):
677 691 self.load_default_context()
678 692
679 693 comment_id = self.request.matchdict['comment_id']
680 694 comment = ChangesetComment.get_or_404(comment_id)
681 695
682 696 if comment.immutable:
683 697 # don't allow deleting comments that are immutable
684 698 raise HTTPForbidden()
685 699
686 700 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
687 701 super_admin = h.HasPermissionAny('hg.admin')()
688 702 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
689 703 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
690 704 comment_repo_admin = is_repo_admin and is_repo_comment
691 705
692 706 if super_admin or comment_owner or comment_repo_admin:
693 707 text = self.request.POST.get('text')
694 708 version = self.request.POST.get('version')
695 709 if text == comment.text:
696 710 log.warning(
697 711 'Comment(repo): '
698 712 'Trying to create new version '
699 713 'with the same comment body {}'.format(
700 714 comment_id,
701 715 )
702 716 )
703 717 raise HTTPNotFound()
704 718
705 719 if version.isdigit():
706 720 version = int(version)
707 721 else:
708 722 log.warning(
709 723 'Comment(repo): Wrong version type {} {} '
710 724 'for comment {}'.format(
711 725 version,
712 726 type(version),
713 727 comment_id,
714 728 )
715 729 )
716 730 raise HTTPNotFound()
717 731
718 732 try:
719 733 comment_history = CommentsModel().edit(
720 734 comment_id=comment_id,
721 735 text=text,
722 736 auth_user=self._rhodecode_user,
723 737 version=version,
724 738 )
725 739 except CommentVersionMismatch:
726 740 raise HTTPConflict()
727 741
728 742 if not comment_history:
729 743 raise HTTPNotFound()
730 744
731 745 commit_id = self.request.matchdict['commit_id']
732 746 commit = self.db_repo.get_commit(commit_id)
733 747 CommentsModel().trigger_commit_comment_hook(
734 748 self.db_repo, self._rhodecode_user, 'edit',
735 749 data={'comment': comment, 'commit': commit})
736 750
737 751 Session().commit()
738 752 return {
739 753 'comment_history_id': comment_history.comment_history_id,
740 754 'comment_id': comment.comment_id,
741 755 'comment_version': comment_history.version,
742 756 'comment_author_username': comment_history.author.username,
743 757 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16),
744 758 'comment_created_on': h.age_component(comment_history.created_on,
745 759 time_is_local=True),
746 760 }
747 761 else:
748 762 log.warning('No permissions for user %s to edit comment_id: %s',
749 763 self._rhodecode_db_user, comment_id)
750 764 raise HTTPNotFound()
751 765
752 766 @LoginRequired()
753 767 @HasRepoPermissionAnyDecorator(
754 768 'repository.read', 'repository.write', 'repository.admin')
755 769 @view_config(
756 770 route_name='repo_commit_data', request_method='GET',
757 771 renderer='json_ext', xhr=True)
758 772 def repo_commit_data(self):
759 773 commit_id = self.request.matchdict['commit_id']
760 774 self.load_default_context()
761 775
762 776 try:
763 777 return self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
764 778 except CommitDoesNotExistError as e:
765 779 return EmptyCommit(message=str(e))
766 780
767 781 @LoginRequired()
768 782 @HasRepoPermissionAnyDecorator(
769 783 'repository.read', 'repository.write', 'repository.admin')
770 784 @view_config(
771 785 route_name='repo_commit_children', request_method='GET',
772 786 renderer='json_ext', xhr=True)
773 787 def repo_commit_children(self):
774 788 commit_id = self.request.matchdict['commit_id']
775 789 self.load_default_context()
776 790
777 791 try:
778 792 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
779 793 children = commit.children
780 794 except CommitDoesNotExistError:
781 795 children = []
782 796
783 797 result = {"results": children}
784 798 return result
785 799
786 800 @LoginRequired()
787 801 @HasRepoPermissionAnyDecorator(
788 802 'repository.read', 'repository.write', 'repository.admin')
789 803 @view_config(
790 804 route_name='repo_commit_parents', request_method='GET',
791 805 renderer='json_ext')
792 806 def repo_commit_parents(self):
793 807 commit_id = self.request.matchdict['commit_id']
794 808 self.load_default_context()
795 809
796 810 try:
797 811 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
798 812 parents = commit.parents
799 813 except CommitDoesNotExistError:
800 814 parents = []
801 815 result = {"results": parents}
802 816 return result
@@ -1,3240 +1,3239 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 @import 'tooltips';
30 30 @import 'sweetalert2';
31 31
32 32
33 33 //--- BASE ------------------//
34 34 .noscript-error {
35 35 top: 0;
36 36 left: 0;
37 37 width: 100%;
38 38 z-index: 101;
39 39 text-align: center;
40 40 font-size: 120%;
41 41 color: white;
42 42 background-color: @alert2;
43 43 padding: 5px 0 5px 0;
44 44 font-weight: @text-semibold-weight;
45 45 font-family: @text-semibold;
46 46 }
47 47
48 48 html {
49 49 display: table;
50 50 height: 100%;
51 51 width: 100%;
52 52 }
53 53
54 54 body {
55 55 display: table-cell;
56 56 width: 100%;
57 57 }
58 58
59 59 //--- LAYOUT ------------------//
60 60
61 61 .hidden{
62 62 display: none !important;
63 63 }
64 64
65 65 .box{
66 66 float: left;
67 67 width: 100%;
68 68 }
69 69
70 70 .browser-header {
71 71 clear: both;
72 72 }
73 73 .main {
74 74 clear: both;
75 75 padding:0 0 @pagepadding;
76 76 height: auto;
77 77
78 78 &:after { //clearfix
79 79 content:"";
80 80 clear:both;
81 81 width:100%;
82 82 display:block;
83 83 }
84 84 }
85 85
86 86 .flex-container {
87 87 display: flex;
88 88 justify-content: space-between;
89 89 }
90 90
91 91 .action-link{
92 92 margin-left: @padding;
93 93 padding-left: @padding;
94 94 border-left: @border-thickness solid @border-default-color;
95 95 }
96 96
97 97 .cursor-pointer {
98 98 cursor: pointer;
99 99 }
100 100
101 101 input + .action-link, .action-link.first{
102 102 border-left: none;
103 103 }
104 104
105 105 .link-disabled {
106 106 color: @grey4;
107 107 cursor: default;
108 108 }
109 109
110 110 .action-link.last{
111 111 margin-right: @padding;
112 112 padding-right: @padding;
113 113 }
114 114
115 115 .action-link.active,
116 116 .action-link.active a{
117 117 color: @grey4;
118 118 }
119 119
120 120 .action-link.disabled {
121 121 color: @grey4;
122 122 cursor: inherit;
123 123 }
124 124
125 125 .grey-link-action {
126 126 cursor: pointer;
127 127 &:hover {
128 128 color: @grey2;
129 129 }
130 130 color: @grey4;
131 131 }
132 132
133 133 .clipboard-action {
134 134 cursor: pointer;
135 135 margin-left: 5px;
136 136
137 137 &:not(.no-grey) {
138 138
139 139 &:hover {
140 140 color: @grey2;
141 141 }
142 142 color: @grey4;
143 143 }
144 144 }
145 145
146 146 ul.simple-list{
147 147 list-style: none;
148 148 margin: 0;
149 149 padding: 0;
150 150 }
151 151
152 152 .main-content {
153 153 padding-bottom: @pagepadding;
154 154 }
155 155
156 156 .wide-mode-wrapper {
157 157 max-width:4000px !important;
158 158 }
159 159
160 160 .wrapper {
161 161 position: relative;
162 162 max-width: @wrapper-maxwidth;
163 163 margin: 0 auto;
164 164 }
165 165
166 166 #content {
167 167 clear: both;
168 168 padding: 0 @contentpadding;
169 169 }
170 170
171 171 .advanced-settings-fields{
172 172 input{
173 173 margin-left: @textmargin;
174 174 margin-right: @padding/2;
175 175 }
176 176 }
177 177
178 178 .cs_files_title {
179 179 margin: @pagepadding 0 0;
180 180 }
181 181
182 182 input.inline[type="file"] {
183 183 display: inline;
184 184 }
185 185
186 186 .error_page {
187 187 margin: 10% auto;
188 188
189 189 h1 {
190 190 color: @grey2;
191 191 }
192 192
193 193 .alert {
194 194 margin: @padding 0;
195 195 }
196 196
197 197 .error-branding {
198 198 color: @grey4;
199 199 font-weight: @text-semibold-weight;
200 200 font-family: @text-semibold;
201 201 }
202 202
203 203 .error_message {
204 204 font-family: @text-regular;
205 205 }
206 206
207 207 .sidebar {
208 208 min-height: 275px;
209 209 margin: 0;
210 210 padding: 0 0 @sidebarpadding @sidebarpadding;
211 211 border: none;
212 212 }
213 213
214 214 .main-content {
215 215 position: relative;
216 216 margin: 0 @sidebarpadding @sidebarpadding;
217 217 padding: 0 0 0 @sidebarpadding;
218 218 border-left: @border-thickness solid @grey5;
219 219
220 220 @media (max-width:767px) {
221 221 clear: both;
222 222 width: 100%;
223 223 margin: 0;
224 224 border: none;
225 225 }
226 226 }
227 227
228 228 .inner-column {
229 229 float: left;
230 230 width: 29.75%;
231 231 min-height: 150px;
232 232 margin: @sidebarpadding 2% 0 0;
233 233 padding: 0 2% 0 0;
234 234 border-right: @border-thickness solid @grey5;
235 235
236 236 @media (max-width:767px) {
237 237 clear: both;
238 238 width: 100%;
239 239 border: none;
240 240 }
241 241
242 242 ul {
243 243 padding-left: 1.25em;
244 244 }
245 245
246 246 &:last-child {
247 247 margin: @sidebarpadding 0 0;
248 248 border: none;
249 249 }
250 250
251 251 h4 {
252 252 margin: 0 0 @padding;
253 253 font-weight: @text-semibold-weight;
254 254 font-family: @text-semibold;
255 255 }
256 256 }
257 257 }
258 258 .error-page-logo {
259 259 width: 130px;
260 260 height: 160px;
261 261 }
262 262
263 263 // HEADER
264 264 .header {
265 265
266 266 min-height: 49px;
267 267 min-width: 1024px;
268 268
269 269 position: relative;
270 270 vertical-align: bottom;
271 271 padding: 0 @header-padding;
272 272 background-color: @grey1;
273 273 color: @grey5;
274 274
275 275 .title {
276 276 overflow: visible;
277 277 }
278 278
279 279 &:before,
280 280 &:after {
281 281 content: "";
282 282 clear: both;
283 283 width: 100%;
284 284 }
285 285
286 286 // TODO: johbo: Avoids breaking "Repositories" chooser
287 287 .select2-container .select2-choice .select2-arrow {
288 288 display: none;
289 289 }
290 290 }
291 291
292 292 #header-inner {
293 293 &.title {
294 294 margin: 0;
295 295 }
296 296 &:before,
297 297 &:after {
298 298 content: "";
299 299 clear: both;
300 300 }
301 301 }
302 302
303 303 // Gists
304 304 #files_data {
305 305 clear: both; //for firefox
306 306 padding-top: 10px;
307 307 }
308 308
309 309 #gistid {
310 310 margin-right: @padding;
311 311 }
312 312
313 313 // Global Settings Editor
314 314 .textarea.editor {
315 315 float: left;
316 316 position: relative;
317 317 max-width: @texteditor-width;
318 318
319 319 select {
320 320 position: absolute;
321 321 top:10px;
322 322 right:0;
323 323 }
324 324
325 325 .CodeMirror {
326 326 margin: 0;
327 327 }
328 328
329 329 .help-block {
330 330 margin: 0 0 @padding;
331 331 padding:.5em;
332 332 background-color: @grey6;
333 333 &.pre-formatting {
334 334 white-space: pre;
335 335 }
336 336 }
337 337 }
338 338
339 339 ul.auth_plugins {
340 340 margin: @padding 0 @padding @legend-width;
341 341 padding: 0;
342 342
343 343 li {
344 344 margin-bottom: @padding;
345 345 line-height: 1em;
346 346 list-style-type: none;
347 347
348 348 .auth_buttons .btn {
349 349 margin-right: @padding;
350 350 }
351 351
352 352 }
353 353 }
354 354
355 355
356 356 // My Account PR list
357 357
358 358 #show_closed {
359 359 margin: 0 1em 0 0;
360 360 }
361 361
362 362 #pull_request_list_table {
363 363 .closed {
364 364 background-color: @grey6;
365 365 }
366 366
367 367 .state-creating,
368 368 .state-updating,
369 369 .state-merging
370 370 {
371 371 background-color: @grey6;
372 372 }
373 373
374 374 .log-container .truncate {
375 375 height: 2.75em;
376 376 white-space: pre-line;
377 377 }
378 378 table.rctable .user {
379 379 padding-left: 0;
380 380 }
381 381 .td-status {
382 382 padding: 0 0px 0px 10px;
383 383 width: 15px;
384 384 }
385 385 table.rctable {
386 386 td.td-description,
387 387 .rc-user {
388 388 min-width: auto;
389 389 }
390 390 }
391 391 }
392 392
393 393 // Pull Requests
394 394
395 395 .pullrequests_section_head {
396 396 display: block;
397 397 clear: both;
398 398 margin: @padding 0;
399 399 font-weight: @text-bold-weight;
400 400 font-family: @text-bold;
401 401 }
402 402
403 403 .pr-commit-flow {
404 404 position: relative;
405 405 font-weight: 600;
406 406
407 407 .tag {
408 408 display: inline-block;
409 409 margin: 0 1em .5em 0;
410 410 }
411 411
412 412 .clone-url {
413 413 display: inline-block;
414 414 margin: 0 0 .5em 0;
415 415 padding: 0;
416 416 line-height: 1.2em;
417 417 }
418 418 }
419 419
420 420 .pr-mergeinfo {
421 421 min-width: 95% !important;
422 422 padding: 0 !important;
423 423 border: 0;
424 424 }
425 425 .pr-mergeinfo-copy {
426 426 padding: 0 0;
427 427 }
428 428
429 429 .pr-pullinfo {
430 430 min-width: 95% !important;
431 431 padding: 0 !important;
432 432 border: 0;
433 433 }
434 434 .pr-pullinfo-copy {
435 435 padding: 0 0;
436 436 }
437 437
438 438 .pr-title-input {
439 439 width: 100%;
440 440 font-size: 18px;
441 441 margin: 0 0 4px 0;
442 442 padding: 0;
443 443 line-height: 1.7em;
444 444 color: @text-color;
445 445 letter-spacing: .02em;
446 446 font-weight: @text-bold-weight;
447 447 font-family: @text-bold;
448 448
449 449 &:hover {
450 450 box-shadow: none;
451 451 }
452 452 }
453 453
454 454 #pr-title {
455 455 input {
456 456 border: 1px transparent;
457 457 color: black;
458 458 opacity: 1;
459 459 background: #fff;
460 460 font-size: 18px;
461 461 }
462 462 }
463 463
464 464 .pr-title-closed-tag {
465 465 font-size: 16px;
466 466 }
467 467
468 468 #pr-desc {
469 469 padding: 10px 0;
470 470
471 471 .markdown-block {
472 472 padding: 0;
473 473 margin-bottom: -30px;
474 474 }
475 475 }
476 476
477 477 #pullrequest_title {
478 478 width: 100%;
479 479 box-sizing: border-box;
480 480 }
481 481
482 482 #pr_open_message {
483 483 border: @border-thickness solid #fff;
484 484 border-radius: @border-radius;
485 485 text-align: left;
486 486 overflow: hidden;
487 487 white-space: pre-line;
488 488 padding-top: 5px
489 489 }
490 490
491 491 #add_reviewer {
492 492 padding-top: 10px;
493 493 }
494 494
495 495 #add_reviewer_input,
496 496 #add_observer_input {
497 497 padding-top: 10px
498 498 }
499 499
500 500 .pr-details-title-author-pref {
501 501 padding-right: 10px
502 502 }
503 503
504 504 .label-pr-detail {
505 505 display: table-cell;
506 506 width: 120px;
507 507 padding-top: 7.5px;
508 508 padding-bottom: 7.5px;
509 509 padding-right: 7.5px;
510 510 }
511 511
512 512 .source-details ul {
513 513 padding: 10px 16px;
514 514 }
515 515
516 516 .source-details-action {
517 517 color: @grey4;
518 518 font-size: 11px
519 519 }
520 520
521 521 .pr-submit-button {
522 522 float: right;
523 523 margin: 0 0 0 5px;
524 524 }
525 525
526 526 .pr-spacing-container {
527 527 padding: 20px;
528 528 clear: both
529 529 }
530 530
531 531 #pr-description-input {
532 532 margin-bottom: 0;
533 533 }
534 534
535 535 .pr-description-label {
536 536 vertical-align: top;
537 537 }
538 538
539 539 #open_edit_pullrequest {
540 540 padding: 0;
541 541 }
542 542
543 543 #close_edit_pullrequest {
544 544
545 545 }
546 546
547 547 #delete_pullrequest {
548 548 clear: inherit;
549 549
550 550 form {
551 551 display: inline;
552 552 }
553 553
554 554 }
555 555
556 556 .perms_section_head {
557 557 min-width: 625px;
558 558
559 559 h2 {
560 560 margin-bottom: 0;
561 561 }
562 562
563 563 .label-checkbox {
564 564 float: left;
565 565 }
566 566
567 567 &.field {
568 568 margin: @space 0 @padding;
569 569 }
570 570
571 571 &:first-child.field {
572 572 margin-top: 0;
573 573
574 574 .label {
575 575 margin-top: 0;
576 576 padding-top: 0;
577 577 }
578 578
579 579 .radios {
580 580 padding-top: 0;
581 581 }
582 582 }
583 583
584 584 .radios {
585 585 position: relative;
586 586 width: 505px;
587 587 }
588 588 }
589 589
590 590 //--- MODULES ------------------//
591 591
592 592
593 593 // Server Announcement
594 594 #server-announcement {
595 595 width: 95%;
596 596 margin: @padding auto;
597 597 padding: @padding;
598 598 border-width: 2px;
599 599 border-style: solid;
600 600 .border-radius(2px);
601 601 font-weight: @text-bold-weight;
602 602 font-family: @text-bold;
603 603
604 604 &.info { border-color: @alert4; background-color: @alert4-inner; }
605 605 &.warning { border-color: @alert3; background-color: @alert3-inner; }
606 606 &.error { border-color: @alert2; background-color: @alert2-inner; }
607 607 &.success { border-color: @alert1; background-color: @alert1-inner; }
608 608 &.neutral { border-color: @grey3; background-color: @grey6; }
609 609 }
610 610
611 611 // Fixed Sidebar Column
612 612 .sidebar-col-wrapper {
613 613 padding-left: @sidebar-all-width;
614 614
615 615 .sidebar {
616 616 width: @sidebar-width;
617 617 margin-left: -@sidebar-all-width;
618 618 }
619 619 }
620 620
621 621 .sidebar-col-wrapper.scw-small {
622 622 padding-left: @sidebar-small-all-width;
623 623
624 624 .sidebar {
625 625 width: @sidebar-small-width;
626 626 margin-left: -@sidebar-small-all-width;
627 627 }
628 628 }
629 629
630 630
631 631 // FOOTER
632 632 #footer {
633 633 padding: 0;
634 634 text-align: center;
635 635 vertical-align: middle;
636 636 color: @grey2;
637 637 font-size: 11px;
638 638
639 639 p {
640 640 margin: 0;
641 641 padding: 1em;
642 642 line-height: 1em;
643 643 }
644 644
645 645 .server-instance { //server instance
646 646 display: none;
647 647 }
648 648
649 649 .title {
650 650 float: none;
651 651 margin: 0 auto;
652 652 }
653 653 }
654 654
655 655 button.close {
656 656 padding: 0;
657 657 cursor: pointer;
658 658 background: transparent;
659 659 border: 0;
660 660 .box-shadow(none);
661 661 -webkit-appearance: none;
662 662 }
663 663
664 664 .close {
665 665 float: right;
666 666 font-size: 21px;
667 667 font-family: @text-bootstrap;
668 668 line-height: 1em;
669 669 font-weight: bold;
670 670 color: @grey2;
671 671
672 672 &:hover,
673 673 &:focus {
674 674 color: @grey1;
675 675 text-decoration: none;
676 676 cursor: pointer;
677 677 }
678 678 }
679 679
680 680 // GRID
681 681 .sorting,
682 682 .sorting_desc,
683 683 .sorting_asc {
684 684 cursor: pointer;
685 685 }
686 686 .sorting_desc:after {
687 687 content: "\00A0\25B2";
688 688 font-size: .75em;
689 689 }
690 690 .sorting_asc:after {
691 691 content: "\00A0\25BC";
692 692 font-size: .68em;
693 693 }
694 694
695 695
696 696 .user_auth_tokens {
697 697
698 698 &.truncate {
699 699 white-space: nowrap;
700 700 overflow: hidden;
701 701 text-overflow: ellipsis;
702 702 }
703 703
704 704 .fields .field .input {
705 705 margin: 0;
706 706 }
707 707
708 708 input#description {
709 709 width: 100px;
710 710 margin: 0;
711 711 }
712 712
713 713 .drop-menu {
714 714 // TODO: johbo: Remove this, should work out of the box when
715 715 // having multiple inputs inline
716 716 margin: 0 0 0 5px;
717 717 }
718 718 }
719 719 #user_list_table {
720 720 .closed {
721 721 background-color: @grey6;
722 722 }
723 723 }
724 724
725 725
726 726 input, textarea {
727 727 &.disabled {
728 728 opacity: .5;
729 729 }
730 730
731 731 &:hover {
732 732 border-color: @grey3;
733 733 box-shadow: @button-shadow;
734 734 }
735 735
736 736 &:focus {
737 737 border-color: @rcblue;
738 738 box-shadow: @button-shadow;
739 739 }
740 740 }
741 741
742 742 // remove extra padding in firefox
743 743 input::-moz-focus-inner { border:0; padding:0 }
744 744
745 745 .adjacent input {
746 746 margin-bottom: @padding;
747 747 }
748 748
749 749 .permissions_boxes {
750 750 display: block;
751 751 }
752 752
753 753 //FORMS
754 754
755 755 .medium-inline,
756 756 input#description.medium-inline {
757 757 display: inline;
758 758 width: @medium-inline-input-width;
759 759 min-width: 100px;
760 760 }
761 761
762 762 select {
763 763 //reset
764 764 -webkit-appearance: none;
765 765 -moz-appearance: none;
766 766
767 767 display: inline-block;
768 768 height: 28px;
769 769 width: auto;
770 770 margin: 0 @padding @padding 0;
771 771 padding: 0 18px 0 8px;
772 772 line-height:1em;
773 773 font-size: @basefontsize;
774 774 border: @border-thickness solid @grey5;
775 775 border-radius: @border-radius;
776 776 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
777 777 color: @grey4;
778 778 box-shadow: @button-shadow;
779 779
780 780 &:after {
781 781 content: "\00A0\25BE";
782 782 }
783 783
784 784 &:focus, &:hover {
785 785 outline: none;
786 786 border-color: @grey4;
787 787 color: @rcdarkblue;
788 788 }
789 789 }
790 790
791 791 option {
792 792 &:focus {
793 793 outline: none;
794 794 }
795 795 }
796 796
797 797 input,
798 798 textarea {
799 799 padding: @input-padding;
800 800 border: @input-border-thickness solid @border-highlight-color;
801 801 .border-radius (@border-radius);
802 802 font-family: @text-light;
803 803 font-size: @basefontsize;
804 804
805 805 &.input-sm {
806 806 padding: 5px;
807 807 }
808 808
809 809 &#description {
810 810 min-width: @input-description-minwidth;
811 811 min-height: 1em;
812 812 padding: 10px;
813 813 }
814 814 }
815 815
816 816 .field-sm {
817 817 input,
818 818 textarea {
819 819 padding: 5px;
820 820 }
821 821 }
822 822
823 823 textarea {
824 824 display: block;
825 825 clear: both;
826 826 width: 100%;
827 827 min-height: 100px;
828 828 margin-bottom: @padding;
829 829 .box-sizing(border-box);
830 830 overflow: auto;
831 831 }
832 832
833 833 label {
834 834 font-family: @text-light;
835 835 }
836 836
837 837 // GRAVATARS
838 838 // centers gravatar on username to the right
839 839
840 840 .gravatar {
841 841 display: inline;
842 842 min-width: 16px;
843 843 min-height: 16px;
844 844 margin: -5px 0;
845 845 padding: 0;
846 846 line-height: 1em;
847 847 box-sizing: content-box;
848 848 border-radius: 50%;
849 849
850 850 &.gravatar-large {
851 851 margin: -0.5em .25em -0.5em 0;
852 852 }
853 853
854 854 & + .user {
855 855 display: inline;
856 856 margin: 0;
857 857 padding: 0 0 0 .17em;
858 858 line-height: 1em;
859 859 }
860 860
861 861 & + .no-margin {
862 862 margin: 0
863 863 }
864 864
865 865 }
866 866
867 867 .user-inline-data {
868 868 display: inline-block;
869 869 float: left;
870 870 padding-left: .5em;
871 871 line-height: 1.3em;
872 872 }
873 873
874 874 .rc-user { // gravatar + user wrapper
875 875 float: left;
876 876 position: relative;
877 877 min-width: 100px;
878 878 max-width: 200px;
879 879 min-height: (@gravatar-size + @border-thickness * 2); // account for border
880 880 display: block;
881 881 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
882 882
883 883
884 884 .gravatar {
885 885 display: block;
886 886 position: absolute;
887 887 top: 0;
888 888 left: 0;
889 889 min-width: @gravatar-size;
890 890 min-height: @gravatar-size;
891 891 margin: 0;
892 892 }
893 893
894 894 .user {
895 895 display: block;
896 896 max-width: 175px;
897 897 padding-top: 2px;
898 898 overflow: hidden;
899 899 text-overflow: ellipsis;
900 900 }
901 901 }
902 902
903 903 .gist-gravatar,
904 904 .journal_container {
905 905 .gravatar-large {
906 906 margin: 0 .5em -10px 0;
907 907 }
908 908 }
909 909
910 910 .gist-type-fields {
911 911 line-height: 30px;
912 912 height: 30px;
913 913
914 914 .gist-type-fields-wrapper {
915 915 vertical-align: middle;
916 916 display: inline-block;
917 917 line-height: 25px;
918 918 }
919 919 }
920 920
921 921 // ADMIN SETTINGS
922 922
923 923 // Tag Patterns
924 924 .tag_patterns {
925 925 .tag_input {
926 926 margin-bottom: @padding;
927 927 }
928 928 }
929 929
930 930 .locked_input {
931 931 position: relative;
932 932
933 933 input {
934 934 display: inline;
935 935 margin: 3px 5px 0px 0px;
936 936 }
937 937
938 938 br {
939 939 display: none;
940 940 }
941 941
942 942 .error-message {
943 943 float: left;
944 944 width: 100%;
945 945 }
946 946
947 947 .lock_input_button {
948 948 display: inline;
949 949 }
950 950
951 951 .help-block {
952 952 clear: both;
953 953 }
954 954 }
955 955
956 956 // Notifications
957 957
958 958 .notifications_buttons {
959 959 margin: 0 0 @space 0;
960 960 padding: 0;
961 961
962 962 .btn {
963 963 display: inline-block;
964 964 }
965 965 }
966 966
967 967 .notification-list {
968 968
969 969 div {
970 970 vertical-align: middle;
971 971 }
972 972
973 973 .container {
974 974 display: block;
975 975 margin: 0 0 @padding 0;
976 976 }
977 977
978 978 .delete-notifications {
979 979 margin-left: @padding;
980 980 text-align: right;
981 981 cursor: pointer;
982 982 }
983 983
984 984 .read-notifications {
985 985 margin-left: @padding/2;
986 986 text-align: right;
987 987 width: 35px;
988 988 cursor: pointer;
989 989 }
990 990
991 991 .icon-minus-sign {
992 992 color: @alert2;
993 993 }
994 994
995 995 .icon-ok-sign {
996 996 color: @alert1;
997 997 }
998 998 }
999 999
1000 1000 .user_settings {
1001 1001 float: left;
1002 1002 clear: both;
1003 1003 display: block;
1004 1004 width: 100%;
1005 1005
1006 1006 .gravatar_box {
1007 1007 margin-bottom: @padding;
1008 1008
1009 1009 &:after {
1010 1010 content: " ";
1011 1011 clear: both;
1012 1012 width: 100%;
1013 1013 }
1014 1014 }
1015 1015
1016 1016 .fields .field {
1017 1017 clear: both;
1018 1018 }
1019 1019 }
1020 1020
1021 1021 .advanced_settings {
1022 1022 margin-bottom: @space;
1023 1023
1024 1024 .help-block {
1025 1025 margin-left: 0;
1026 1026 }
1027 1027
1028 1028 button + .help-block {
1029 1029 margin-top: @padding;
1030 1030 }
1031 1031 }
1032 1032
1033 1033 // admin settings radio buttons and labels
1034 1034 .label-2 {
1035 1035 float: left;
1036 1036 width: @label2-width;
1037 1037
1038 1038 label {
1039 1039 color: @grey1;
1040 1040 }
1041 1041 }
1042 1042 .checkboxes {
1043 1043 float: left;
1044 1044 width: @checkboxes-width;
1045 1045 margin-bottom: @padding;
1046 1046
1047 1047 .checkbox {
1048 1048 width: 100%;
1049 1049
1050 1050 label {
1051 1051 margin: 0;
1052 1052 padding: 0;
1053 1053 }
1054 1054 }
1055 1055
1056 1056 .checkbox + .checkbox {
1057 1057 display: inline-block;
1058 1058 }
1059 1059
1060 1060 label {
1061 1061 margin-right: 1em;
1062 1062 }
1063 1063 }
1064 1064
1065 1065 // CHANGELOG
1066 1066 .container_header {
1067 1067 float: left;
1068 1068 display: block;
1069 1069 width: 100%;
1070 1070 margin: @padding 0 @padding;
1071 1071
1072 1072 #filter_changelog {
1073 1073 float: left;
1074 1074 margin-right: @padding;
1075 1075 }
1076 1076
1077 1077 .breadcrumbs_light {
1078 1078 display: inline-block;
1079 1079 }
1080 1080 }
1081 1081
1082 1082 .info_box {
1083 1083 float: right;
1084 1084 }
1085 1085
1086 1086
1087 1087
1088 1088 #graph_content{
1089 1089
1090 1090 // adjust for table headers so that graph renders properly
1091 1091 // #graph_nodes padding - table cell padding
1092 1092 padding-top: (@space - (@basefontsize * 2.4));
1093 1093
1094 1094 &.graph_full_width {
1095 1095 width: 100%;
1096 1096 max-width: 100%;
1097 1097 }
1098 1098 }
1099 1099
1100 1100 #graph {
1101 1101
1102 1102 .pagination-left {
1103 1103 float: left;
1104 1104 clear: both;
1105 1105 }
1106 1106
1107 1107 .log-container {
1108 1108 max-width: 345px;
1109 1109
1110 1110 .message{
1111 1111 max-width: 340px;
1112 1112 }
1113 1113 }
1114 1114
1115 1115 .graph-col-wrapper {
1116 1116
1117 1117 #graph_nodes {
1118 1118 width: 100px;
1119 1119 position: absolute;
1120 1120 left: 70px;
1121 1121 z-index: -1;
1122 1122 }
1123 1123 }
1124 1124
1125 1125 .load-more-commits {
1126 1126 text-align: center;
1127 1127 }
1128 1128 .load-more-commits:hover {
1129 1129 background-color: @grey7;
1130 1130 }
1131 1131 .load-more-commits {
1132 1132 a {
1133 1133 display: block;
1134 1134 }
1135 1135 }
1136 1136 }
1137 1137
1138 1138 .obsolete-toggle {
1139 1139 line-height: 30px;
1140 1140 margin-left: -15px;
1141 1141 }
1142 1142
1143 #rev_range_container, #rev_range_clear, #rev_range_more {
1144 margin-top: -5px;
1145 margin-bottom: -5px;
1143 #rev_range_action {
1144 margin-bottom: -8px;
1146 1145 }
1147 1146
1148 1147 #filter_changelog {
1149 1148 float: left;
1150 1149 }
1151 1150
1152 1151
1153 1152 //--- THEME ------------------//
1154 1153
1155 1154 #logo {
1156 1155 float: left;
1157 1156 margin: 9px 0 0 0;
1158 1157
1159 1158 .header {
1160 1159 background-color: transparent;
1161 1160 }
1162 1161
1163 1162 a {
1164 1163 display: inline-block;
1165 1164 }
1166 1165
1167 1166 img {
1168 1167 height:30px;
1169 1168 }
1170 1169 }
1171 1170
1172 1171 .logo-wrapper {
1173 1172 float:left;
1174 1173 }
1175 1174
1176 1175 .branding {
1177 1176 float: left;
1178 1177 padding: 9px 2px;
1179 1178 line-height: 1em;
1180 1179 font-size: @navigation-fontsize;
1181 1180
1182 1181 a {
1183 1182 color: @grey5
1184 1183 }
1185 1184
1186 1185 // 1024px or smaller
1187 1186 @media screen and (max-width: 1180px) {
1188 1187 display: none;
1189 1188 }
1190 1189
1191 1190 }
1192 1191
1193 1192 img {
1194 1193 border: none;
1195 1194 outline: none;
1196 1195 }
1197 1196 user-profile-header
1198 1197 label {
1199 1198
1200 1199 input[type="checkbox"] {
1201 1200 margin-right: 1em;
1202 1201 }
1203 1202 input[type="radio"] {
1204 1203 margin-right: 1em;
1205 1204 }
1206 1205 }
1207 1206
1208 1207 .review-status {
1209 1208 &.under_review {
1210 1209 color: @alert3;
1211 1210 }
1212 1211 &.approved {
1213 1212 color: @alert1;
1214 1213 }
1215 1214 &.rejected,
1216 1215 &.forced_closed{
1217 1216 color: @alert2;
1218 1217 }
1219 1218 &.not_reviewed {
1220 1219 color: @grey5;
1221 1220 }
1222 1221 }
1223 1222
1224 1223 .review-status-under_review {
1225 1224 color: @alert3;
1226 1225 }
1227 1226 .status-tag-under_review {
1228 1227 border-color: @alert3;
1229 1228 }
1230 1229
1231 1230 .review-status-approved {
1232 1231 color: @alert1;
1233 1232 }
1234 1233 .status-tag-approved {
1235 1234 border-color: @alert1;
1236 1235 }
1237 1236
1238 1237 .review-status-rejected,
1239 1238 .review-status-forced_closed {
1240 1239 color: @alert2;
1241 1240 }
1242 1241 .status-tag-rejected,
1243 1242 .status-tag-forced_closed {
1244 1243 border-color: @alert2;
1245 1244 }
1246 1245
1247 1246 .review-status-not_reviewed {
1248 1247 color: @grey5;
1249 1248 }
1250 1249 .status-tag-not_reviewed {
1251 1250 border-color: @grey5;
1252 1251 }
1253 1252
1254 1253 .test_pattern_preview {
1255 1254 margin: @space 0;
1256 1255
1257 1256 p {
1258 1257 margin-bottom: 0;
1259 1258 border-bottom: @border-thickness solid @border-default-color;
1260 1259 color: @grey3;
1261 1260 }
1262 1261
1263 1262 .btn {
1264 1263 margin-bottom: @padding;
1265 1264 }
1266 1265 }
1267 1266 #test_pattern_result {
1268 1267 display: none;
1269 1268 &:extend(pre);
1270 1269 padding: .9em;
1271 1270 color: @grey3;
1272 1271 background-color: @grey7;
1273 1272 border-right: @border-thickness solid @border-default-color;
1274 1273 border-bottom: @border-thickness solid @border-default-color;
1275 1274 border-left: @border-thickness solid @border-default-color;
1276 1275 }
1277 1276
1278 1277 #repo_vcs_settings {
1279 1278 #inherit_overlay_vcs_default {
1280 1279 display: none;
1281 1280 }
1282 1281 #inherit_overlay_vcs_custom {
1283 1282 display: custom;
1284 1283 }
1285 1284 &.inherited {
1286 1285 #inherit_overlay_vcs_default {
1287 1286 display: block;
1288 1287 }
1289 1288 #inherit_overlay_vcs_custom {
1290 1289 display: none;
1291 1290 }
1292 1291 }
1293 1292 }
1294 1293
1295 1294 .issue-tracker-link {
1296 1295 color: @rcblue;
1297 1296 }
1298 1297
1299 1298 // Issue Tracker Table Show/Hide
1300 1299 #repo_issue_tracker {
1301 1300 #inherit_overlay {
1302 1301 display: none;
1303 1302 }
1304 1303 #custom_overlay {
1305 1304 display: custom;
1306 1305 }
1307 1306 &.inherited {
1308 1307 #inherit_overlay {
1309 1308 display: block;
1310 1309 }
1311 1310 #custom_overlay {
1312 1311 display: none;
1313 1312 }
1314 1313 }
1315 1314 }
1316 1315 table.issuetracker {
1317 1316 &.readonly {
1318 1317 tr, td {
1319 1318 color: @grey3;
1320 1319 }
1321 1320 }
1322 1321 .edit {
1323 1322 display: none;
1324 1323 }
1325 1324 .editopen {
1326 1325 .edit {
1327 1326 display: inline;
1328 1327 }
1329 1328 .entry {
1330 1329 display: none;
1331 1330 }
1332 1331 }
1333 1332 tr td.td-action {
1334 1333 min-width: 117px;
1335 1334 }
1336 1335 td input {
1337 1336 max-width: none;
1338 1337 min-width: 30px;
1339 1338 width: 80%;
1340 1339 }
1341 1340 .issuetracker_pref input {
1342 1341 width: 40%;
1343 1342 }
1344 1343 input.edit_issuetracker_update {
1345 1344 margin-right: 0;
1346 1345 width: auto;
1347 1346 }
1348 1347 }
1349 1348
1350 1349 table.integrations {
1351 1350 .td-icon {
1352 1351 width: 20px;
1353 1352 .integration-icon {
1354 1353 height: 20px;
1355 1354 width: 20px;
1356 1355 }
1357 1356 }
1358 1357 }
1359 1358
1360 1359 .integrations {
1361 1360 a.integration-box {
1362 1361 color: @text-color;
1363 1362 &:hover {
1364 1363 .panel {
1365 1364 background: #fbfbfb;
1366 1365 }
1367 1366 }
1368 1367 .integration-icon {
1369 1368 width: 30px;
1370 1369 height: 30px;
1371 1370 margin-right: 20px;
1372 1371 float: left;
1373 1372 }
1374 1373
1375 1374 .panel-body {
1376 1375 padding: 10px;
1377 1376 }
1378 1377 .panel {
1379 1378 margin-bottom: 10px;
1380 1379 }
1381 1380 h2 {
1382 1381 display: inline-block;
1383 1382 margin: 0;
1384 1383 min-width: 140px;
1385 1384 }
1386 1385 }
1387 1386 a.integration-box.dummy-integration {
1388 1387 color: @grey4
1389 1388 }
1390 1389 }
1391 1390
1392 1391 //Permissions Settings
1393 1392 #add_perm {
1394 1393 margin: 0 0 @padding;
1395 1394 cursor: pointer;
1396 1395 }
1397 1396
1398 1397 .perm_ac {
1399 1398 input {
1400 1399 width: 95%;
1401 1400 }
1402 1401 }
1403 1402
1404 1403 .autocomplete-suggestions {
1405 1404 width: auto !important; // overrides autocomplete.js
1406 1405 min-width: 278px;
1407 1406 margin: 0;
1408 1407 border: @border-thickness solid @grey5;
1409 1408 border-radius: @border-radius;
1410 1409 color: @grey2;
1411 1410 background-color: white;
1412 1411 }
1413 1412
1414 1413 .autocomplete-qfilter-suggestions {
1415 1414 width: auto !important; // overrides autocomplete.js
1416 1415 max-height: 100% !important;
1417 1416 min-width: 376px;
1418 1417 margin: 0;
1419 1418 border: @border-thickness solid @grey5;
1420 1419 color: @grey2;
1421 1420 background-color: white;
1422 1421 }
1423 1422
1424 1423 .autocomplete-selected {
1425 1424 background: #F0F0F0;
1426 1425 }
1427 1426
1428 1427 .ac-container-wrap {
1429 1428 margin: 0;
1430 1429 padding: 8px;
1431 1430 border-bottom: @border-thickness solid @grey5;
1432 1431 list-style-type: none;
1433 1432 cursor: pointer;
1434 1433
1435 1434 &:hover {
1436 1435 background-color: @grey7;
1437 1436 }
1438 1437
1439 1438 img {
1440 1439 height: @gravatar-size;
1441 1440 width: @gravatar-size;
1442 1441 margin-right: 1em;
1443 1442 }
1444 1443
1445 1444 strong {
1446 1445 font-weight: normal;
1447 1446 }
1448 1447 }
1449 1448
1450 1449 // Settings Dropdown
1451 1450 .user-menu .container {
1452 1451 padding: 0 4px;
1453 1452 margin: 0;
1454 1453 }
1455 1454
1456 1455 .user-menu .gravatar {
1457 1456 cursor: pointer;
1458 1457 }
1459 1458
1460 1459 .codeblock {
1461 1460 margin-bottom: @padding;
1462 1461 clear: both;
1463 1462
1464 1463 .stats {
1465 1464 overflow: hidden;
1466 1465 }
1467 1466
1468 1467 .message{
1469 1468 textarea{
1470 1469 margin: 0;
1471 1470 }
1472 1471 }
1473 1472
1474 1473 .code-header {
1475 1474 .stats {
1476 1475 line-height: 2em;
1477 1476
1478 1477 .revision_id {
1479 1478 margin-left: 0;
1480 1479 }
1481 1480 .buttons {
1482 1481 padding-right: 0;
1483 1482 }
1484 1483 }
1485 1484
1486 1485 .item{
1487 1486 margin-right: 0.5em;
1488 1487 }
1489 1488 }
1490 1489
1491 1490 #editor_container {
1492 1491 position: relative;
1493 1492 margin: @padding 10px;
1494 1493 }
1495 1494 }
1496 1495
1497 1496 #file_history_container {
1498 1497 display: none;
1499 1498 }
1500 1499
1501 1500 .file-history-inner {
1502 1501 margin-bottom: 10px;
1503 1502 }
1504 1503
1505 1504 // Pull Requests
1506 1505 .summary-details {
1507 1506 width: 100%;
1508 1507 }
1509 1508 .pr-summary {
1510 1509 border-bottom: @border-thickness solid @grey5;
1511 1510 margin-bottom: @space;
1512 1511 }
1513 1512
1514 1513 .reviewers {
1515 1514 width: 98%;
1516 1515 }
1517 1516
1518 1517 .reviewers ul li {
1519 1518 position: relative;
1520 1519 width: 100%;
1521 1520 padding-bottom: 8px;
1522 1521 list-style-type: none;
1523 1522 }
1524 1523
1525 1524 .reviewer_entry {
1526 1525 min-height: 55px;
1527 1526 }
1528 1527
1529 1528 .reviewer_reason {
1530 1529 padding-left: 20px;
1531 1530 line-height: 1.5em;
1532 1531 }
1533 1532 .reviewer_status {
1534 1533 display: inline-block;
1535 1534 width: 20px;
1536 1535 min-width: 20px;
1537 1536 height: 1.2em;
1538 1537 line-height: 1em;
1539 1538 }
1540 1539
1541 1540 .reviewer_name {
1542 1541 display: inline-block;
1543 1542 max-width: 83%;
1544 1543 padding-right: 20px;
1545 1544 vertical-align: middle;
1546 1545 line-height: 1;
1547 1546
1548 1547 .rc-user {
1549 1548 min-width: 0;
1550 1549 margin: -2px 1em 0 0;
1551 1550 }
1552 1551
1553 1552 .reviewer {
1554 1553 float: left;
1555 1554 }
1556 1555 }
1557 1556
1558 1557 .reviewer_member_mandatory {
1559 1558 width: 16px;
1560 1559 font-size: 11px;
1561 1560 margin: 0;
1562 1561 padding: 0;
1563 1562 color: black;
1564 1563 opacity: 0.4;
1565 1564 }
1566 1565
1567 1566 .reviewer_member_mandatory_remove,
1568 1567 .reviewer_member_remove {
1569 1568 width: 16px;
1570 1569 padding: 0;
1571 1570 color: black;
1572 1571 cursor: pointer;
1573 1572 }
1574 1573
1575 1574 .reviewer_member_mandatory_remove {
1576 1575 color: @grey4;
1577 1576 }
1578 1577
1579 1578 .reviewer_member_status {
1580 1579 margin-top: 5px;
1581 1580 }
1582 1581 .pr-summary #summary{
1583 1582 width: 100%;
1584 1583 }
1585 1584 .pr-summary .action_button:hover {
1586 1585 border: 0;
1587 1586 cursor: pointer;
1588 1587 }
1589 1588 .pr-details-title {
1590 1589 height: 20px;
1591 1590 line-height: 16px;
1592 1591
1593 1592 padding-bottom: 4px;
1594 1593 border-bottom: @border-thickness solid @grey5;
1595 1594
1596 1595 .action_button.disabled {
1597 1596 color: @grey4;
1598 1597 cursor: inherit;
1599 1598 }
1600 1599 .action_button {
1601 1600 color: @rcblue;
1602 1601 }
1603 1602 }
1604 1603 .pr-details-content {
1605 1604 margin-top: @textmargin - 5;
1606 1605 margin-bottom: @textmargin - 5;
1607 1606 }
1608 1607
1609 1608 .pr-reviewer-rules {
1610 1609 padding: 10px 0px 20px 0px;
1611 1610 }
1612 1611
1613 1612 .todo-resolved {
1614 1613 text-decoration: line-through;
1615 1614 }
1616 1615
1617 1616 .todo-table, .comments-table {
1618 1617 width: 100%;
1619 1618
1620 1619 td {
1621 1620 padding: 5px 0px;
1622 1621 }
1623 1622
1624 1623 .td-todo-number {
1625 1624 text-align: left;
1626 1625 white-space: nowrap;
1627 1626 width: 1%;
1628 1627 padding-right: 2px;
1629 1628 }
1630 1629
1631 1630 .td-todo-gravatar {
1632 1631 width: 5%;
1633 1632
1634 1633 img {
1635 1634 margin: -3px 0;
1636 1635 }
1637 1636 }
1638 1637
1639 1638 }
1640 1639
1641 1640 .todo-comment-text-wrapper {
1642 1641 display: inline-grid;
1643 1642 }
1644 1643
1645 1644 .todo-comment-text {
1646 1645 margin-left: 5px;
1647 1646 white-space: nowrap;
1648 1647 overflow: hidden;
1649 1648 text-overflow: ellipsis;
1650 1649 }
1651 1650
1652 1651 table.group_members {
1653 1652 width: 100%
1654 1653 }
1655 1654
1656 1655 .group_members {
1657 1656 margin-top: 0;
1658 1657 padding: 0;
1659 1658
1660 1659 img {
1661 1660 height: @gravatar-size;
1662 1661 width: @gravatar-size;
1663 1662 margin-right: .5em;
1664 1663 margin-left: 3px;
1665 1664 }
1666 1665
1667 1666 .to-delete {
1668 1667 .user {
1669 1668 text-decoration: line-through;
1670 1669 }
1671 1670 }
1672 1671 }
1673 1672
1674 1673 .compare_view_commits_title {
1675 1674 .disabled {
1676 1675 cursor: inherit;
1677 1676 &:hover{
1678 1677 background-color: inherit;
1679 1678 color: inherit;
1680 1679 }
1681 1680 }
1682 1681 }
1683 1682
1684 1683 .subtitle-compare {
1685 1684 margin: -15px 0px 0px 0px;
1686 1685 }
1687 1686
1688 1687 // new entry in group_members
1689 1688 .td-author-new-entry {
1690 1689 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1691 1690 }
1692 1691
1693 1692 .usergroup_member_remove {
1694 1693 width: 16px;
1695 1694 margin-bottom: 10px;
1696 1695 padding: 0;
1697 1696 color: black !important;
1698 1697 cursor: pointer;
1699 1698 }
1700 1699
1701 1700 .reviewer_ac .ac-input {
1702 1701 width: 98%;
1703 1702 margin-bottom: 1em;
1704 1703 }
1705 1704
1706 1705 .observer_ac .ac-input {
1707 1706 width: 98%;
1708 1707 margin-bottom: 1em;
1709 1708 }
1710 1709
1711 1710 .rule-table {
1712 1711 width: 100%;
1713 1712 }
1714 1713
1715 1714 .rule-table td {
1716 1715
1717 1716 }
1718 1717
1719 1718 .rule-table .td-role {
1720 1719 width: 100px
1721 1720 }
1722 1721
1723 1722 .rule-table .td-mandatory {
1724 1723 width: 100px
1725 1724 }
1726 1725
1727 1726 .rule-table .td-group-votes {
1728 1727 width: 150px
1729 1728 }
1730 1729
1731 1730 .compare_view_commits tr{
1732 1731 height: 20px;
1733 1732 }
1734 1733 .compare_view_commits td {
1735 1734 vertical-align: top;
1736 1735 padding-top: 10px;
1737 1736 }
1738 1737 .compare_view_commits .author {
1739 1738 margin-left: 5px;
1740 1739 }
1741 1740
1742 1741 .compare_view_commits {
1743 1742 .color-a {
1744 1743 color: @alert1;
1745 1744 }
1746 1745
1747 1746 .color-c {
1748 1747 color: @color3;
1749 1748 }
1750 1749
1751 1750 .color-r {
1752 1751 color: @color5;
1753 1752 }
1754 1753
1755 1754 .color-a-bg {
1756 1755 background-color: @alert1;
1757 1756 }
1758 1757
1759 1758 .color-c-bg {
1760 1759 background-color: @alert3;
1761 1760 }
1762 1761
1763 1762 .color-r-bg {
1764 1763 background-color: @alert2;
1765 1764 }
1766 1765
1767 1766 .color-a-border {
1768 1767 border: 1px solid @alert1;
1769 1768 }
1770 1769
1771 1770 .color-c-border {
1772 1771 border: 1px solid @alert3;
1773 1772 }
1774 1773
1775 1774 .color-r-border {
1776 1775 border: 1px solid @alert2;
1777 1776 }
1778 1777
1779 1778 .commit-change-indicator {
1780 1779 width: 15px;
1781 1780 height: 15px;
1782 1781 position: relative;
1783 1782 left: 15px;
1784 1783 }
1785 1784
1786 1785 .commit-change-content {
1787 1786 text-align: center;
1788 1787 vertical-align: middle;
1789 1788 line-height: 15px;
1790 1789 }
1791 1790 }
1792 1791
1793 1792 .compare_view_filepath {
1794 1793 color: @grey1;
1795 1794 }
1796 1795
1797 1796 .show_more {
1798 1797 display: inline-block;
1799 1798 width: 0;
1800 1799 height: 0;
1801 1800 vertical-align: middle;
1802 1801 content: "";
1803 1802 border: 4px solid;
1804 1803 border-right-color: transparent;
1805 1804 border-bottom-color: transparent;
1806 1805 border-left-color: transparent;
1807 1806 font-size: 0;
1808 1807 }
1809 1808
1810 1809 .journal_more .show_more {
1811 1810 display: inline;
1812 1811
1813 1812 &:after {
1814 1813 content: none;
1815 1814 }
1816 1815 }
1817 1816
1818 1817 .compare_view_commits .collapse_commit:after {
1819 1818 cursor: pointer;
1820 1819 content: "\00A0\25B4";
1821 1820 margin-left: -3px;
1822 1821 font-size: 17px;
1823 1822 color: @grey4;
1824 1823 }
1825 1824
1826 1825 .diff_links {
1827 1826 margin-left: 8px;
1828 1827 }
1829 1828
1830 1829 #pull_request_overview {
1831 1830 div.ancestor {
1832 1831 margin: -33px 0;
1833 1832 }
1834 1833 }
1835 1834
1836 1835 div.ancestor {
1837 1836
1838 1837 }
1839 1838
1840 1839 .cs_icon_td input[type="checkbox"] {
1841 1840 display: none;
1842 1841 }
1843 1842
1844 1843 .cs_icon_td .expand_file_icon:after {
1845 1844 cursor: pointer;
1846 1845 content: "\00A0\25B6";
1847 1846 font-size: 12px;
1848 1847 color: @grey4;
1849 1848 }
1850 1849
1851 1850 .cs_icon_td .collapse_file_icon:after {
1852 1851 cursor: pointer;
1853 1852 content: "\00A0\25BC";
1854 1853 font-size: 12px;
1855 1854 color: @grey4;
1856 1855 }
1857 1856
1858 1857 /*new binary
1859 1858 NEW_FILENODE = 1
1860 1859 DEL_FILENODE = 2
1861 1860 MOD_FILENODE = 3
1862 1861 RENAMED_FILENODE = 4
1863 1862 COPIED_FILENODE = 5
1864 1863 CHMOD_FILENODE = 6
1865 1864 BIN_FILENODE = 7
1866 1865 */
1867 1866 .cs_files_expand {
1868 1867 font-size: @basefontsize + 5px;
1869 1868 line-height: 1.8em;
1870 1869 float: right;
1871 1870 }
1872 1871
1873 1872 .cs_files_expand span{
1874 1873 color: @rcblue;
1875 1874 cursor: pointer;
1876 1875 }
1877 1876 .cs_files {
1878 1877 clear: both;
1879 1878 padding-bottom: @padding;
1880 1879
1881 1880 .cur_cs {
1882 1881 margin: 10px 2px;
1883 1882 font-weight: bold;
1884 1883 }
1885 1884
1886 1885 .node {
1887 1886 float: left;
1888 1887 }
1889 1888
1890 1889 .changes {
1891 1890 float: right;
1892 1891 color: white;
1893 1892 font-size: @basefontsize - 4px;
1894 1893 margin-top: 4px;
1895 1894 opacity: 0.6;
1896 1895 filter: Alpha(opacity=60); /* IE8 and earlier */
1897 1896
1898 1897 .added {
1899 1898 background-color: @alert1;
1900 1899 float: left;
1901 1900 text-align: center;
1902 1901 }
1903 1902
1904 1903 .deleted {
1905 1904 background-color: @alert2;
1906 1905 float: left;
1907 1906 text-align: center;
1908 1907 }
1909 1908
1910 1909 .bin {
1911 1910 background-color: @alert1;
1912 1911 text-align: center;
1913 1912 }
1914 1913
1915 1914 /*new binary*/
1916 1915 .bin.bin1 {
1917 1916 background-color: @alert1;
1918 1917 text-align: center;
1919 1918 }
1920 1919
1921 1920 /*deleted binary*/
1922 1921 .bin.bin2 {
1923 1922 background-color: @alert2;
1924 1923 text-align: center;
1925 1924 }
1926 1925
1927 1926 /*mod binary*/
1928 1927 .bin.bin3 {
1929 1928 background-color: @grey2;
1930 1929 text-align: center;
1931 1930 }
1932 1931
1933 1932 /*rename file*/
1934 1933 .bin.bin4 {
1935 1934 background-color: @alert4;
1936 1935 text-align: center;
1937 1936 }
1938 1937
1939 1938 /*copied file*/
1940 1939 .bin.bin5 {
1941 1940 background-color: @alert4;
1942 1941 text-align: center;
1943 1942 }
1944 1943
1945 1944 /*chmod file*/
1946 1945 .bin.bin6 {
1947 1946 background-color: @grey2;
1948 1947 text-align: center;
1949 1948 }
1950 1949 }
1951 1950 }
1952 1951
1953 1952 .cs_files .cs_added, .cs_files .cs_A,
1954 1953 .cs_files .cs_added, .cs_files .cs_M,
1955 1954 .cs_files .cs_added, .cs_files .cs_D {
1956 1955 height: 16px;
1957 1956 padding-right: 10px;
1958 1957 margin-top: 7px;
1959 1958 text-align: left;
1960 1959 }
1961 1960
1962 1961 .cs_icon_td {
1963 1962 min-width: 16px;
1964 1963 width: 16px;
1965 1964 }
1966 1965
1967 1966 .pull-request-merge {
1968 1967 border: 1px solid @grey5;
1969 1968 padding: 10px 0px 20px;
1970 1969 margin-top: 10px;
1971 1970 margin-bottom: 20px;
1972 1971 }
1973 1972
1974 1973 .pull-request-merge-refresh {
1975 1974 margin: 2px 7px;
1976 1975 a {
1977 1976 color: @grey3;
1978 1977 }
1979 1978 }
1980 1979
1981 1980 .pull-request-merge ul {
1982 1981 padding: 0px 0px;
1983 1982 }
1984 1983
1985 1984 .pull-request-merge li {
1986 1985 list-style-type: none;
1987 1986 }
1988 1987
1989 1988 .pull-request-merge .pull-request-wrap {
1990 1989 height: auto;
1991 1990 padding: 0px 0px;
1992 1991 text-align: right;
1993 1992 }
1994 1993
1995 1994 .pull-request-merge span {
1996 1995 margin-right: 5px;
1997 1996 }
1998 1997
1999 1998 .pull-request-merge-actions {
2000 1999 min-height: 30px;
2001 2000 padding: 0px 0px;
2002 2001 }
2003 2002
2004 2003 .pull-request-merge-info {
2005 2004 padding: 0px 5px 5px 0px;
2006 2005 }
2007 2006
2008 2007 .merge-status {
2009 2008 margin-right: 5px;
2010 2009 }
2011 2010
2012 2011 .merge-message {
2013 2012 font-size: 1.2em
2014 2013 }
2015 2014
2016 2015 .merge-message.success i,
2017 2016 .merge-icon.success i {
2018 2017 color:@alert1;
2019 2018 }
2020 2019
2021 2020 .merge-message.warning i,
2022 2021 .merge-icon.warning i {
2023 2022 color: @alert3;
2024 2023 }
2025 2024
2026 2025 .merge-message.error i,
2027 2026 .merge-icon.error i {
2028 2027 color:@alert2;
2029 2028 }
2030 2029
2031 2030 .pr-versions {
2032 2031 font-size: 1.1em;
2033 2032 padding: 7.5px;
2034 2033
2035 2034 table {
2036 2035
2037 2036 }
2038 2037
2039 2038 td {
2040 2039 line-height: 15px;
2041 2040 }
2042 2041
2043 2042 .compare-radio-button {
2044 2043 position: relative;
2045 2044 top: -3px;
2046 2045 }
2047 2046 }
2048 2047
2049 2048
2050 2049 #close_pull_request {
2051 2050 margin-right: 0px;
2052 2051 }
2053 2052
2054 2053 .empty_data {
2055 2054 color: @grey4;
2056 2055 }
2057 2056
2058 2057 #changeset_compare_view_content {
2059 2058 clear: both;
2060 2059 width: 100%;
2061 2060 box-sizing: border-box;
2062 2061 .border-radius(@border-radius);
2063 2062
2064 2063 .help-block {
2065 2064 margin: @padding 0;
2066 2065 color: @text-color;
2067 2066 &.pre-formatting {
2068 2067 white-space: pre;
2069 2068 }
2070 2069 }
2071 2070
2072 2071 .empty_data {
2073 2072 margin: @padding 0;
2074 2073 }
2075 2074
2076 2075 .alert {
2077 2076 margin-bottom: @space;
2078 2077 }
2079 2078 }
2080 2079
2081 2080 .table_disp {
2082 2081 .status {
2083 2082 width: auto;
2084 2083 }
2085 2084 }
2086 2085
2087 2086
2088 2087 .creation_in_progress {
2089 2088 color: @grey4
2090 2089 }
2091 2090
2092 2091 .status_box_menu {
2093 2092 margin: 0;
2094 2093 }
2095 2094
2096 2095 .notification-table{
2097 2096 margin-bottom: @space;
2098 2097 display: table;
2099 2098 width: 100%;
2100 2099
2101 2100 .container{
2102 2101 display: table-row;
2103 2102
2104 2103 .notification-header{
2105 2104 border-bottom: @border-thickness solid @border-default-color;
2106 2105 }
2107 2106
2108 2107 .notification-subject{
2109 2108 display: table-cell;
2110 2109 }
2111 2110 }
2112 2111 }
2113 2112
2114 2113 // Notifications
2115 2114 .notification-header{
2116 2115 display: table;
2117 2116 width: 100%;
2118 2117 padding: floor(@basefontsize/2) 0;
2119 2118 line-height: 1em;
2120 2119
2121 2120 .desc, .delete-notifications, .read-notifications{
2122 2121 display: table-cell;
2123 2122 text-align: left;
2124 2123 }
2125 2124
2126 2125 .delete-notifications, .read-notifications{
2127 2126 width: 35px;
2128 2127 min-width: 35px; //fixes when only one button is displayed
2129 2128 }
2130 2129 }
2131 2130
2132 2131 .notification-body {
2133 2132 .markdown-block,
2134 2133 .rst-block {
2135 2134 padding: @padding 0;
2136 2135 }
2137 2136
2138 2137 .notification-subject {
2139 2138 padding: @textmargin 0;
2140 2139 border-bottom: @border-thickness solid @border-default-color;
2141 2140 }
2142 2141 }
2143 2142
2144 2143 .notice-messages {
2145 2144 .markdown-block,
2146 2145 .rst-block {
2147 2146 padding: 0;
2148 2147 }
2149 2148 }
2150 2149
2151 2150 .notifications_buttons{
2152 2151 float: right;
2153 2152 }
2154 2153
2155 2154 #notification-status{
2156 2155 display: inline;
2157 2156 }
2158 2157
2159 2158 // Repositories
2160 2159
2161 2160 #summary.fields{
2162 2161 display: table;
2163 2162
2164 2163 .field{
2165 2164 display: table-row;
2166 2165
2167 2166 .label-summary{
2168 2167 display: table-cell;
2169 2168 min-width: @label-summary-minwidth;
2170 2169 padding-top: @padding/2;
2171 2170 padding-bottom: @padding/2;
2172 2171 padding-right: @padding/2;
2173 2172 }
2174 2173
2175 2174 .input{
2176 2175 display: table-cell;
2177 2176 padding: @padding/2;
2178 2177
2179 2178 input{
2180 2179 min-width: 29em;
2181 2180 padding: @padding/4;
2182 2181 }
2183 2182 }
2184 2183 .statistics, .downloads{
2185 2184 .disabled{
2186 2185 color: @grey4;
2187 2186 }
2188 2187 }
2189 2188 }
2190 2189 }
2191 2190
2192 2191 #summary{
2193 2192 width: 70%;
2194 2193 }
2195 2194
2196 2195
2197 2196 // Journal
2198 2197 .journal.title {
2199 2198 h5 {
2200 2199 float: left;
2201 2200 margin: 0;
2202 2201 width: 70%;
2203 2202 }
2204 2203
2205 2204 ul {
2206 2205 float: right;
2207 2206 display: inline-block;
2208 2207 margin: 0;
2209 2208 width: 30%;
2210 2209 text-align: right;
2211 2210
2212 2211 li {
2213 2212 display: inline;
2214 2213 font-size: @journal-fontsize;
2215 2214 line-height: 1em;
2216 2215
2217 2216 list-style-type: none;
2218 2217 }
2219 2218 }
2220 2219 }
2221 2220
2222 2221 .filterexample {
2223 2222 position: absolute;
2224 2223 top: 95px;
2225 2224 left: @contentpadding;
2226 2225 color: @rcblue;
2227 2226 font-size: 11px;
2228 2227 font-family: @text-regular;
2229 2228 cursor: help;
2230 2229
2231 2230 &:hover {
2232 2231 color: @rcdarkblue;
2233 2232 }
2234 2233
2235 2234 @media (max-width:768px) {
2236 2235 position: relative;
2237 2236 top: auto;
2238 2237 left: auto;
2239 2238 display: block;
2240 2239 }
2241 2240 }
2242 2241
2243 2242
2244 2243 #journal{
2245 2244 margin-bottom: @space;
2246 2245
2247 2246 .journal_day{
2248 2247 margin-bottom: @textmargin/2;
2249 2248 padding-bottom: @textmargin/2;
2250 2249 font-size: @journal-fontsize;
2251 2250 border-bottom: @border-thickness solid @border-default-color;
2252 2251 }
2253 2252
2254 2253 .journal_container{
2255 2254 margin-bottom: @space;
2256 2255
2257 2256 .journal_user{
2258 2257 display: inline-block;
2259 2258 }
2260 2259 .journal_action_container{
2261 2260 display: block;
2262 2261 margin-top: @textmargin;
2263 2262
2264 2263 div{
2265 2264 display: inline;
2266 2265 }
2267 2266
2268 2267 div.journal_action_params{
2269 2268 display: block;
2270 2269 }
2271 2270
2272 2271 div.journal_repo:after{
2273 2272 content: "\A";
2274 2273 white-space: pre;
2275 2274 }
2276 2275
2277 2276 div.date{
2278 2277 display: block;
2279 2278 margin-bottom: @textmargin;
2280 2279 }
2281 2280 }
2282 2281 }
2283 2282 }
2284 2283
2285 2284 // Files
2286 2285 .edit-file-title {
2287 2286 font-size: 16px;
2288 2287
2289 2288 .title-heading {
2290 2289 padding: 2px;
2291 2290 }
2292 2291 }
2293 2292
2294 2293 .edit-file-fieldset {
2295 2294 margin: @sidebarpadding 0;
2296 2295
2297 2296 .fieldset {
2298 2297 .left-label {
2299 2298 width: 13%;
2300 2299 }
2301 2300 .right-content {
2302 2301 width: 87%;
2303 2302 max-width: 100%;
2304 2303 }
2305 2304 .filename-label {
2306 2305 margin-top: 13px;
2307 2306 }
2308 2307 .commit-message-label {
2309 2308 margin-top: 4px;
2310 2309 }
2311 2310 .file-upload-input {
2312 2311 input {
2313 2312 display: none;
2314 2313 }
2315 2314 margin-top: 10px;
2316 2315 }
2317 2316 .file-upload-label {
2318 2317 margin-top: 10px;
2319 2318 }
2320 2319 p {
2321 2320 margin-top: 5px;
2322 2321 }
2323 2322
2324 2323 }
2325 2324 .custom-path-link {
2326 2325 margin-left: 5px;
2327 2326 }
2328 2327 #commit {
2329 2328 resize: vertical;
2330 2329 }
2331 2330 }
2332 2331
2333 2332 .delete-file-preview {
2334 2333 max-height: 250px;
2335 2334 }
2336 2335
2337 2336 .new-file,
2338 2337 #filter_activate,
2339 2338 #filter_deactivate {
2340 2339 float: right;
2341 2340 margin: 0 0 0 10px;
2342 2341 }
2343 2342
2344 2343 .file-upload-transaction-wrapper {
2345 2344 margin-top: 57px;
2346 2345 clear: both;
2347 2346 }
2348 2347
2349 2348 .file-upload-transaction-wrapper .error {
2350 2349 color: @color5;
2351 2350 }
2352 2351
2353 2352 .file-upload-transaction {
2354 2353 min-height: 200px;
2355 2354 padding: 54px;
2356 2355 border: 1px solid @grey5;
2357 2356 text-align: center;
2358 2357 clear: both;
2359 2358 }
2360 2359
2361 2360 .file-upload-transaction i {
2362 2361 font-size: 48px
2363 2362 }
2364 2363
2365 2364 h3.files_location{
2366 2365 line-height: 2.4em;
2367 2366 }
2368 2367
2369 2368 .browser-nav {
2370 2369 width: 100%;
2371 2370 display: table;
2372 2371 margin-bottom: 20px;
2373 2372
2374 2373 .info_box {
2375 2374 float: left;
2376 2375 display: inline-table;
2377 2376 height: 2.5em;
2378 2377
2379 2378 .browser-cur-rev, .info_box_elem {
2380 2379 display: table-cell;
2381 2380 vertical-align: middle;
2382 2381 }
2383 2382
2384 2383 .drop-menu {
2385 2384 margin: 0 10px;
2386 2385 }
2387 2386
2388 2387 .info_box_elem {
2389 2388 border-top: @border-thickness solid @grey5;
2390 2389 border-bottom: @border-thickness solid @grey5;
2391 2390 box-shadow: @button-shadow;
2392 2391
2393 2392 #at_rev, a {
2394 2393 padding: 0.6em 0.4em;
2395 2394 margin: 0;
2396 2395 .box-shadow(none);
2397 2396 border: 0;
2398 2397 height: 12px;
2399 2398 color: @grey2;
2400 2399 }
2401 2400
2402 2401 input#at_rev {
2403 2402 max-width: 50px;
2404 2403 text-align: center;
2405 2404 }
2406 2405
2407 2406 &.previous {
2408 2407 border: @border-thickness solid @grey5;
2409 2408 border-top-left-radius: @border-radius;
2410 2409 border-bottom-left-radius: @border-radius;
2411 2410
2412 2411 &:hover {
2413 2412 border-color: @grey4;
2414 2413 }
2415 2414
2416 2415 .disabled {
2417 2416 color: @grey5;
2418 2417 cursor: not-allowed;
2419 2418 opacity: 0.5;
2420 2419 }
2421 2420 }
2422 2421
2423 2422 &.next {
2424 2423 border: @border-thickness solid @grey5;
2425 2424 border-top-right-radius: @border-radius;
2426 2425 border-bottom-right-radius: @border-radius;
2427 2426
2428 2427 &:hover {
2429 2428 border-color: @grey4;
2430 2429 }
2431 2430
2432 2431 .disabled {
2433 2432 color: @grey5;
2434 2433 cursor: not-allowed;
2435 2434 opacity: 0.5;
2436 2435 }
2437 2436 }
2438 2437 }
2439 2438
2440 2439 .browser-cur-rev {
2441 2440
2442 2441 span{
2443 2442 margin: 0;
2444 2443 color: @rcblue;
2445 2444 height: 12px;
2446 2445 display: inline-block;
2447 2446 padding: 0.7em 1em ;
2448 2447 border: @border-thickness solid @rcblue;
2449 2448 margin-right: @padding;
2450 2449 }
2451 2450 }
2452 2451
2453 2452 }
2454 2453
2455 2454 .select-index-number {
2456 2455 margin: 0 0 0 20px;
2457 2456 color: @grey3;
2458 2457 }
2459 2458
2460 2459 .search_activate {
2461 2460 display: table-cell;
2462 2461 vertical-align: middle;
2463 2462
2464 2463 input, label{
2465 2464 margin: 0;
2466 2465 padding: 0;
2467 2466 }
2468 2467
2469 2468 input{
2470 2469 margin-left: @textmargin;
2471 2470 }
2472 2471
2473 2472 }
2474 2473 }
2475 2474
2476 2475 .browser-cur-rev{
2477 2476 margin-bottom: @textmargin;
2478 2477 }
2479 2478
2480 2479 #node_filter_box_loading{
2481 2480 .info_text;
2482 2481 }
2483 2482
2484 2483 .browser-search {
2485 2484 margin: -25px 0px 5px 0px;
2486 2485 }
2487 2486
2488 2487 .files-quick-filter {
2489 2488 float: right;
2490 2489 width: 180px;
2491 2490 position: relative;
2492 2491 }
2493 2492
2494 2493 .files-filter-box {
2495 2494 display: flex;
2496 2495 padding: 0px;
2497 2496 border-radius: 3px;
2498 2497 margin-bottom: 0;
2499 2498
2500 2499 a {
2501 2500 border: none !important;
2502 2501 }
2503 2502
2504 2503 li {
2505 2504 list-style-type: none
2506 2505 }
2507 2506 }
2508 2507
2509 2508 .files-filter-box-path {
2510 2509 line-height: 33px;
2511 2510 padding: 0;
2512 2511 width: 20px;
2513 2512 position: absolute;
2514 2513 z-index: 11;
2515 2514 left: 5px;
2516 2515 }
2517 2516
2518 2517 .files-filter-box-input {
2519 2518 margin-right: 0;
2520 2519
2521 2520 input {
2522 2521 border: 1px solid @white;
2523 2522 padding-left: 25px;
2524 2523 width: 145px;
2525 2524
2526 2525 &:hover {
2527 2526 border-color: @grey6;
2528 2527 }
2529 2528
2530 2529 &:focus {
2531 2530 border-color: @grey5;
2532 2531 }
2533 2532 }
2534 2533 }
2535 2534
2536 2535 .browser-result{
2537 2536 td a{
2538 2537 margin-left: 0.5em;
2539 2538 display: inline-block;
2540 2539
2541 2540 em {
2542 2541 font-weight: @text-bold-weight;
2543 2542 font-family: @text-bold;
2544 2543 }
2545 2544 }
2546 2545 }
2547 2546
2548 2547 .browser-highlight{
2549 2548 background-color: @grey5-alpha;
2550 2549 }
2551 2550
2552 2551
2553 2552 .edit-file-fieldset #location,
2554 2553 .edit-file-fieldset #filename {
2555 2554 display: flex;
2556 2555 width: -moz-available; /* WebKit-based browsers will ignore this. */
2557 2556 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2558 2557 width: fill-available;
2559 2558 border: 0;
2560 2559 }
2561 2560
2562 2561 .path-items {
2563 2562 display: flex;
2564 2563 padding: 0;
2565 2564 border: 1px solid #eeeeee;
2566 2565 width: 100%;
2567 2566 float: left;
2568 2567
2569 2568 .breadcrumb-path {
2570 2569 line-height: 30px;
2571 2570 padding: 0 4px;
2572 2571 white-space: nowrap;
2573 2572 }
2574 2573
2575 2574 .upload-form {
2576 2575 margin-top: 46px;
2577 2576 }
2578 2577
2579 2578 .location-path {
2580 2579 width: -moz-available; /* WebKit-based browsers will ignore this. */
2581 2580 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2582 2581 width: fill-available;
2583 2582
2584 2583 .file-name-input {
2585 2584 padding: 0.5em 0;
2586 2585 }
2587 2586
2588 2587 }
2589 2588
2590 2589 ul {
2591 2590 display: flex;
2592 2591 margin: 0;
2593 2592 padding: 0;
2594 2593 width: 100%;
2595 2594 }
2596 2595
2597 2596 li {
2598 2597 list-style-type: none;
2599 2598 }
2600 2599
2601 2600 }
2602 2601
2603 2602 .editor-items {
2604 2603 height: 40px;
2605 2604 margin: 10px 0 -17px 10px;
2606 2605
2607 2606 .editor-action {
2608 2607 cursor: pointer;
2609 2608 }
2610 2609
2611 2610 .editor-action.active {
2612 2611 border-bottom: 2px solid #5C5C5C;
2613 2612 }
2614 2613
2615 2614 li {
2616 2615 list-style-type: none;
2617 2616 }
2618 2617 }
2619 2618
2620 2619 .edit-file-fieldset .message textarea {
2621 2620 border: 1px solid #eeeeee;
2622 2621 }
2623 2622
2624 2623 #files_data .codeblock {
2625 2624 background-color: #F5F5F5;
2626 2625 }
2627 2626
2628 2627 #editor_preview {
2629 2628 background: white;
2630 2629 }
2631 2630
2632 2631 .show-editor {
2633 2632 padding: 10px;
2634 2633 background-color: white;
2635 2634
2636 2635 }
2637 2636
2638 2637 .show-preview {
2639 2638 padding: 10px;
2640 2639 background-color: white;
2641 2640 border-left: 1px solid #eeeeee;
2642 2641 }
2643 2642 // quick filter
2644 2643 .grid-quick-filter {
2645 2644 float: right;
2646 2645 position: relative;
2647 2646 }
2648 2647
2649 2648 .grid-filter-box {
2650 2649 display: flex;
2651 2650 padding: 0px;
2652 2651 border-radius: 3px;
2653 2652 margin-bottom: 0;
2654 2653
2655 2654 a {
2656 2655 border: none !important;
2657 2656 }
2658 2657
2659 2658 li {
2660 2659 list-style-type: none
2661 2660 }
2662 2661
2663 2662 }
2664 2663
2665 2664 .grid-filter-box-icon {
2666 2665 line-height: 33px;
2667 2666 padding: 0;
2668 2667 width: 20px;
2669 2668 position: absolute;
2670 2669 z-index: 11;
2671 2670 left: 5px;
2672 2671 }
2673 2672
2674 2673 .grid-filter-box-input {
2675 2674 margin-right: 0;
2676 2675
2677 2676 input {
2678 2677 border: 1px solid @white;
2679 2678 padding-left: 25px;
2680 2679 width: 145px;
2681 2680
2682 2681 &:hover {
2683 2682 border-color: @grey6;
2684 2683 }
2685 2684
2686 2685 &:focus {
2687 2686 border-color: @grey5;
2688 2687 }
2689 2688 }
2690 2689 }
2691 2690
2692 2691
2693 2692
2694 2693 // Search
2695 2694
2696 2695 .search-form{
2697 2696 #q {
2698 2697 width: @search-form-width;
2699 2698 }
2700 2699 .fields{
2701 2700 margin: 0 0 @space;
2702 2701 }
2703 2702
2704 2703 label{
2705 2704 display: inline-block;
2706 2705 margin-right: @textmargin;
2707 2706 padding-top: 0.25em;
2708 2707 }
2709 2708
2710 2709
2711 2710 .results{
2712 2711 clear: both;
2713 2712 margin: 0 0 @padding;
2714 2713 }
2715 2714
2716 2715 .search-tags {
2717 2716 padding: 5px 0;
2718 2717 }
2719 2718 }
2720 2719
2721 2720 div.search-feedback-items {
2722 2721 display: inline-block;
2723 2722 }
2724 2723
2725 2724 div.search-code-body {
2726 2725 background-color: #ffffff; padding: 5px 0 5px 10px;
2727 2726 pre {
2728 2727 .match { background-color: #faffa6;}
2729 2728 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2730 2729 }
2731 2730 }
2732 2731
2733 2732 .expand_commit.search {
2734 2733 .show_more.open {
2735 2734 height: auto;
2736 2735 max-height: none;
2737 2736 }
2738 2737 }
2739 2738
2740 2739 .search-results {
2741 2740
2742 2741 h2 {
2743 2742 margin-bottom: 0;
2744 2743 }
2745 2744 .codeblock {
2746 2745 border: none;
2747 2746 background: transparent;
2748 2747 }
2749 2748
2750 2749 .codeblock-header {
2751 2750 border: none;
2752 2751 background: transparent;
2753 2752 }
2754 2753
2755 2754 .code-body {
2756 2755 border: @border-thickness solid @grey6;
2757 2756 .border-radius(@border-radius);
2758 2757 }
2759 2758
2760 2759 .td-commit {
2761 2760 &:extend(pre);
2762 2761 border-bottom: @border-thickness solid @border-default-color;
2763 2762 }
2764 2763
2765 2764 .message {
2766 2765 height: auto;
2767 2766 max-width: 350px;
2768 2767 white-space: normal;
2769 2768 text-overflow: initial;
2770 2769 overflow: visible;
2771 2770
2772 2771 .match { background-color: #faffa6;}
2773 2772 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2774 2773 }
2775 2774
2776 2775 .path {
2777 2776 border-bottom: none !important;
2778 2777 border-left: 1px solid @grey6 !important;
2779 2778 border-right: 1px solid @grey6 !important;
2780 2779 }
2781 2780 }
2782 2781
2783 2782 table.rctable td.td-search-results div {
2784 2783 max-width: 100%;
2785 2784 }
2786 2785
2787 2786 #tip-box, .tip-box{
2788 2787 padding: @menupadding/2;
2789 2788 display: block;
2790 2789 border: @border-thickness solid @border-highlight-color;
2791 2790 .border-radius(@border-radius);
2792 2791 background-color: white;
2793 2792 z-index: 99;
2794 2793 white-space: pre-wrap;
2795 2794 }
2796 2795
2797 2796 #linktt {
2798 2797 width: 79px;
2799 2798 }
2800 2799
2801 2800 #help_kb .modal-content{
2802 2801 max-width: 800px;
2803 2802 margin: 10% auto;
2804 2803
2805 2804 table{
2806 2805 td,th{
2807 2806 border-bottom: none;
2808 2807 line-height: 2.5em;
2809 2808 }
2810 2809 th{
2811 2810 padding-bottom: @textmargin/2;
2812 2811 }
2813 2812 td.keys{
2814 2813 text-align: center;
2815 2814 }
2816 2815 }
2817 2816
2818 2817 .block-left{
2819 2818 width: 45%;
2820 2819 margin-right: 5%;
2821 2820 }
2822 2821 .modal-footer{
2823 2822 clear: both;
2824 2823 }
2825 2824 .key.tag{
2826 2825 padding: 0.5em;
2827 2826 background-color: @rcblue;
2828 2827 color: white;
2829 2828 border-color: @rcblue;
2830 2829 .box-shadow(none);
2831 2830 }
2832 2831 }
2833 2832
2834 2833
2835 2834
2836 2835 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2837 2836
2838 2837 @import 'statistics-graph';
2839 2838 @import 'tables';
2840 2839 @import 'forms';
2841 2840 @import 'diff';
2842 2841 @import 'summary';
2843 2842 @import 'navigation';
2844 2843
2845 2844 //--- SHOW/HIDE SECTIONS --//
2846 2845
2847 2846 .btn-collapse {
2848 2847 float: right;
2849 2848 text-align: right;
2850 2849 font-family: @text-light;
2851 2850 font-size: @basefontsize;
2852 2851 cursor: pointer;
2853 2852 border: none;
2854 2853 color: @rcblue;
2855 2854 }
2856 2855
2857 2856 table.rctable,
2858 2857 table.dataTable {
2859 2858 .btn-collapse {
2860 2859 float: right;
2861 2860 text-align: right;
2862 2861 }
2863 2862 }
2864 2863
2865 2864 table.rctable {
2866 2865 &.permissions {
2867 2866
2868 2867 th.td-owner {
2869 2868 padding: 0;
2870 2869 }
2871 2870
2872 2871 th {
2873 2872 font-weight: normal;
2874 2873 padding: 0 5px;
2875 2874 }
2876 2875
2877 2876 }
2878 2877 }
2879 2878
2880 2879
2881 2880 // TODO: johbo: Fix for IE10, this avoids that we see a border
2882 2881 // and padding around checkboxes and radio boxes. Move to the right place,
2883 2882 // or better: Remove this once we did the form refactoring.
2884 2883 input[type=checkbox],
2885 2884 input[type=radio] {
2886 2885 padding: 0;
2887 2886 border: none;
2888 2887 }
2889 2888
2890 2889 .toggle-ajax-spinner{
2891 2890 height: 16px;
2892 2891 width: 16px;
2893 2892 }
2894 2893
2895 2894
2896 2895 .markup-form .clearfix {
2897 2896 .border-radius(@border-radius);
2898 2897 margin: 0px;
2899 2898 }
2900 2899
2901 2900 .markup-form-area {
2902 2901 padding: 8px 12px;
2903 2902 border: 1px solid @grey4;
2904 2903 .border-radius(@border-radius);
2905 2904 }
2906 2905
2907 2906 .markup-form-area-header .nav-links {
2908 2907 display: flex;
2909 2908 flex-flow: row wrap;
2910 2909 -webkit-flex-flow: row wrap;
2911 2910 width: 100%;
2912 2911 }
2913 2912
2914 2913 .markup-form-area-footer {
2915 2914 display: flex;
2916 2915 }
2917 2916
2918 2917 .markup-form-area-footer .toolbar {
2919 2918
2920 2919 }
2921 2920
2922 2921 // markup Form
2923 2922 div.markup-form {
2924 2923 margin-top: 20px;
2925 2924 }
2926 2925
2927 2926 .markup-form strong {
2928 2927 display: block;
2929 2928 margin-bottom: 15px;
2930 2929 }
2931 2930
2932 2931 .markup-form textarea {
2933 2932 width: 100%;
2934 2933 height: 100px;
2935 2934 font-family: @text-monospace;
2936 2935 }
2937 2936
2938 2937 form.markup-form {
2939 2938 margin-top: 10px;
2940 2939 margin-left: 10px;
2941 2940 }
2942 2941
2943 2942 .markup-form .comment-block-ta,
2944 2943 .markup-form .preview-box {
2945 2944 .border-radius(@border-radius);
2946 2945 .box-sizing(border-box);
2947 2946 background-color: white;
2948 2947 }
2949 2948
2950 2949 .markup-form .preview-box.unloaded {
2951 2950 height: 50px;
2952 2951 text-align: center;
2953 2952 padding: 20px;
2954 2953 background-color: white;
2955 2954 }
2956 2955
2957 2956
2958 2957 .dropzone-wrapper {
2959 2958 border: 1px solid @grey5;
2960 2959 padding: 20px;
2961 2960 }
2962 2961
2963 2962 .dropzone,
2964 2963 .dropzone-pure {
2965 2964 border: 2px dashed @grey5;
2966 2965 border-radius: 5px;
2967 2966 background: white;
2968 2967 min-height: 200px;
2969 2968 padding: 54px;
2970 2969
2971 2970 .dz-message {
2972 2971 font-weight: 700;
2973 2972 text-align: center;
2974 2973 margin: 2em 0;
2975 2974 }
2976 2975
2977 2976 }
2978 2977
2979 2978 .dz-preview {
2980 2979 margin: 10px 0 !important;
2981 2980 position: relative;
2982 2981 vertical-align: top;
2983 2982 padding: 10px;
2984 2983 border-bottom: 1px solid @grey5;
2985 2984 }
2986 2985
2987 2986 .dz-filename {
2988 2987 font-weight: 700;
2989 2988 float: left;
2990 2989 }
2991 2990
2992 2991 .dz-sending {
2993 2992 float: right;
2994 2993 }
2995 2994
2996 2995 .dz-response {
2997 2996 clear: both
2998 2997 }
2999 2998
3000 2999 .dz-filename-size {
3001 3000 float: right
3002 3001 }
3003 3002
3004 3003 .dz-error-message {
3005 3004 color: @alert2;
3006 3005 padding-top: 10px;
3007 3006 clear: both;
3008 3007 }
3009 3008
3010 3009
3011 3010 .user-hovercard {
3012 3011 padding: 5px;
3013 3012 }
3014 3013
3015 3014 .user-hovercard-icon {
3016 3015 display: inline;
3017 3016 padding: 0;
3018 3017 box-sizing: content-box;
3019 3018 border-radius: 50%;
3020 3019 float: left;
3021 3020 }
3022 3021
3023 3022 .user-hovercard-name {
3024 3023 float: right;
3025 3024 vertical-align: top;
3026 3025 padding-left: 10px;
3027 3026 min-width: 150px;
3028 3027 }
3029 3028
3030 3029 .user-hovercard-bio {
3031 3030 clear: both;
3032 3031 padding-top: 10px;
3033 3032 }
3034 3033
3035 3034 .user-hovercard-header {
3036 3035 clear: both;
3037 3036 min-height: 10px;
3038 3037 }
3039 3038
3040 3039 .user-hovercard-footer {
3041 3040 clear: both;
3042 3041 min-height: 10px;
3043 3042 }
3044 3043
3045 3044 .user-group-hovercard {
3046 3045 padding: 5px;
3047 3046 }
3048 3047
3049 3048 .user-group-hovercard-icon {
3050 3049 display: inline;
3051 3050 padding: 0;
3052 3051 box-sizing: content-box;
3053 3052 border-radius: 50%;
3054 3053 float: left;
3055 3054 }
3056 3055
3057 3056 .user-group-hovercard-name {
3058 3057 float: left;
3059 3058 vertical-align: top;
3060 3059 padding-left: 10px;
3061 3060 min-width: 150px;
3062 3061 }
3063 3062
3064 3063 .user-group-hovercard-icon i {
3065 3064 border: 1px solid @grey4;
3066 3065 border-radius: 4px;
3067 3066 }
3068 3067
3069 3068 .user-group-hovercard-bio {
3070 3069 clear: both;
3071 3070 padding-top: 10px;
3072 3071 line-height: 1.0em;
3073 3072 }
3074 3073
3075 3074 .user-group-hovercard-header {
3076 3075 clear: both;
3077 3076 min-height: 10px;
3078 3077 }
3079 3078
3080 3079 .user-group-hovercard-footer {
3081 3080 clear: both;
3082 3081 min-height: 10px;
3083 3082 }
3084 3083
3085 3084 .pr-hovercard-header {
3086 3085 clear: both;
3087 3086 display: block;
3088 3087 line-height: 20px;
3089 3088 }
3090 3089
3091 3090 .pr-hovercard-user {
3092 3091 display: flex;
3093 3092 align-items: center;
3094 3093 padding-left: 5px;
3095 3094 }
3096 3095
3097 3096 .pr-hovercard-title {
3098 3097 padding-top: 5px;
3099 3098 }
3100 3099
3101 3100 .action-divider {
3102 3101 opacity: 0.5;
3103 3102 }
3104 3103
3105 3104 .details-inline-block {
3106 3105 display: inline-block;
3107 3106 position: relative;
3108 3107 }
3109 3108
3110 3109 .details-inline-block summary {
3111 3110 list-style: none;
3112 3111 }
3113 3112
3114 3113 details:not([open]) > :not(summary) {
3115 3114 display: none !important;
3116 3115 }
3117 3116
3118 3117 .details-reset > summary {
3119 3118 list-style: none;
3120 3119 }
3121 3120
3122 3121 .details-reset > summary::-webkit-details-marker {
3123 3122 display: none;
3124 3123 }
3125 3124
3126 3125 .details-dropdown {
3127 3126 position: absolute;
3128 3127 top: 100%;
3129 3128 width: 185px;
3130 3129 list-style: none;
3131 3130 background-color: #fff;
3132 3131 background-clip: padding-box;
3133 3132 border: 1px solid @grey5;
3134 3133 box-shadow: 0 8px 24px rgba(149, 157, 165, .2);
3135 3134 left: -150px;
3136 3135 text-align: left;
3137 3136 z-index: 90;
3138 3137 }
3139 3138
3140 3139 .dropdown-divider {
3141 3140 display: block;
3142 3141 height: 0;
3143 3142 margin: 8px 0;
3144 3143 border-top: 1px solid @grey5;
3145 3144 }
3146 3145
3147 3146 .dropdown-item {
3148 3147 display: block;
3149 3148 padding: 4px 8px 4px 16px;
3150 3149 overflow: hidden;
3151 3150 text-overflow: ellipsis;
3152 3151 white-space: nowrap;
3153 3152 font-weight: normal;
3154 3153 }
3155 3154
3156 3155 .right-sidebar {
3157 3156 position: fixed;
3158 3157 top: 0px;
3159 3158 bottom: 0;
3160 3159 right: 0;
3161 3160
3162 3161 background: #fafafa;
3163 3162 z-index: 50;
3164 3163 }
3165 3164
3166 3165 .right-sidebar {
3167 3166 border-left: 1px solid @grey5;
3168 3167 }
3169 3168
3170 3169 .right-sidebar.right-sidebar-expanded {
3171 3170 width: 300px;
3172 3171 overflow: scroll;
3173 3172 }
3174 3173
3175 3174 .right-sidebar.right-sidebar-collapsed {
3176 3175 width: 40px;
3177 3176 padding: 0;
3178 3177 display: block;
3179 3178 overflow: hidden;
3180 3179 }
3181 3180
3182 3181 .sidenav {
3183 3182 float: right;
3184 3183 will-change: min-height;
3185 3184 background: #fafafa;
3186 3185 width: 100%;
3187 3186 }
3188 3187
3189 3188 .sidebar-toggle {
3190 3189 height: 30px;
3191 3190 text-align: center;
3192 3191 margin: 15px 0px 0 0;
3193 3192 }
3194 3193
3195 3194 .sidebar-toggle a {
3196 3195
3197 3196 }
3198 3197
3199 3198 .sidebar-content {
3200 3199 margin-left: 15px;
3201 3200 margin-right: 15px;
3202 3201 }
3203 3202
3204 3203 .sidebar-heading {
3205 3204 font-size: 1.2em;
3206 3205 font-weight: 700;
3207 3206 margin-top: 10px;
3208 3207 }
3209 3208
3210 3209 .sidebar-element {
3211 3210 margin-top: 20px;
3212 3211
3213 3212 .icon-draft {
3214 3213 color: @color-draft
3215 3214 }
3216 3215 }
3217 3216
3218 3217
3219 3218 .right-sidebar-collapsed-state {
3220 3219 display: flex;
3221 3220 flex-direction: column;
3222 3221 justify-content: center;
3223 3222 align-items: center;
3224 3223 padding: 0 10px;
3225 3224 cursor: pointer;
3226 3225 font-size: 1.3em;
3227 3226 margin: 0 -15px;
3228 3227 }
3229 3228
3230 3229 .right-sidebar-collapsed-state:hover {
3231 3230 background-color: @grey5;
3232 3231 }
3233 3232
3234 3233 .old-comments-marker {
3235 3234 text-align: left;
3236 3235 }
3237 3236
3238 3237 .old-comments-marker td {
3239 3238 padding-top: 15px;
3240 3239 }
@@ -1,326 +1,353 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.mako"/>
4 4
5 5 <%def name="title()">
6 6 ${_('%s Changelog') % c.repo_name}
7 7 %if c.changelog_for_path:
8 8 /${c.changelog_for_path}
9 9 %endif
10 10 %if c.rhodecode_name:
11 11 &middot; ${h.branding(c.rhodecode_name)}
12 12 %endif
13 13 </%def>
14 14
15 15 <%def name="breadcrumbs_links()">
16 16 %if c.changelog_for_path:
17 17 /${c.changelog_for_path}
18 18 %endif
19 19 </%def>
20 20
21 21 <%def name="menu_bar_nav()">
22 22 ${self.menu_items(active='repositories')}
23 23 </%def>
24 24
25 25 <%def name="menu_bar_subnav()">
26 26 ${self.repo_menu(active='commits')}
27 27 </%def>
28 28
29 29 <%def name="main()">
30 30
31 31 <div class="box">
32 32
33 33 <div class="title">
34 34 <div id="filter_changelog">
35 35 ${h.hidden('branch_filter')}
36 36 %if c.selected_name:
37 37 <div class="btn btn-default" id="clear_filter" >
38 38 ${_('Clear filter')}
39 39 </div>
40 40 %endif
41 41 </div>
42 42 <div class="pull-left obsolete-toggle">
43 43 % if h.is_hg(c.rhodecode_repo):
44 44 % if c.show_hidden:
45 45 <a class="action-link" href="${h.current_route_path(request, evolve=0)}">${_('Hide obsolete/hidden')}</a>
46 46 % else:
47 47 <a class="action-link" href="${h.current_route_path(request, evolve=1)}">${_('Show obsolete/hidden')}</a>
48 48 % endif
49 49 % else:
50 50 <span class="action-link disabled">${_('Show hidden')}</span>
51 51 % endif
52 52 </div>
53 53 <ul class="links">
54 54 <li>
55 55
56 56 %if c.rhodecode_db_repo.fork:
57 57 <span>
58 58 <a id="compare_fork_button"
59 59 title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
60 60 class="btn btn-small"
61 61 href="${h.route_path('repo_compare',
62 62 repo_name=c.rhodecode_db_repo.fork.repo_name,
63 63 source_ref_type=c.rhodecode_db_repo.landing_ref_type,
64 64 source_ref=c.rhodecode_db_repo.landing_ref_name,
65 65 target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_ref_type,
66 66 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_ref_name,
67 67 _query=dict(merge=1, target_repo=c.repo_name))}"
68 68 >
69 69 ${_('Compare fork with Parent (%s)' % c.rhodecode_db_repo.fork.repo_name)}
70 70 </a>
71 71 </span>
72 72 %endif
73 73
74 74 ## pr open link
75 75 %if h.is_hg(c.rhodecode_repo) or h.is_git(c.rhodecode_repo):
76 76 <span>
77 77 <a id="open_new_pull_request" class="btn btn-small btn-success" href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">
78 78 ${_('Open new pull request')}
79 79 </a>
80 80 </span>
81 81 %endif
82 82
83 83 </li>
84 84 </ul>
85 85 </div>
86 86
87 87 % if c.pagination:
88 88 <script type="text/javascript" src="${h.asset('js/src/plugins/jquery.commits-graph.js')}"></script>
89 89
90 90 <div class="graph-header">
91 91 ${self.breadcrumbs('breadcrumbs_light')}
92 92 </div>
93 93
94 94 <div id="graph">
95 95 <div class="graph-col-wrapper">
96 96 <div id="graph_nodes">
97 97 <div id="graph_canvas"></div>
98 98 </div>
99 99 <div id="graph_content" class="graph_full_width">
100 100
101 101 <div class="table">
102 102 <table id="changesets" class="rctable table-bordered">
103 103 <tr>
104 104 ## checkbox
105 105 <th colspan="4">
106 106 ## clear selection
107 107 <div title="${_('Clear selection')}" class="btn btn-sm" id="rev_range_clear" style="display:none">
108 108 <i class="icon-cancel-circled2"></i>
109 109 </div>
110 110 <div class="btn btn-sm disabled" disabled="disabled" id="rev_range_more" style="display:none;">${_('Select second commit')}</div>
111 <a href="#" class="btn btn-success btn-sm" id="rev_range_container" style="display:none;"></a>
111
112 <div id="rev_range_action" class="btn-group btn-group-actions" style="display:none;">
113 <a href="#" class="btn btn-success btn-sm" id="rev_range_container" style="display:none;"></a>
114
115 <a class="btn btn-success btn-sm btn-more-option" data-toggle="dropdown" aria-pressed="false" role="button">
116 <i class="icon-down"></i>
117 </a>
118
119 <div class="btn-action-switcher-container right-align">
120 <ul class="btn-action-switcher" role="menu" style="min-width: 220px; width: max-content">
121 <li>
122 ## JS fills the URL
123 <a id="rev_range_combined_url" class="btn btn-primary btn-sm" href="">
124 ${_('Show combined diff')}
125 </a>
126 </li>
127 </ul>
128 </div>
129 </div>
130
112 131 </th>
113 132
114 133 ## commit message expand arrow
115 134 <th></th>
116 135 <th>${_('Commit Message')}</th>
117 136
118 137 <th>${_('Age')}</th>
119 138 <th>${_('Author')}</th>
120 139
121 140 <th>${_('Refs')}</th>
122 141 ## comments
123 142 <th></th>
124 143 </tr>
125 144
126 145 <tbody class="commits-range">
127 146 <%include file='changelog_elements.mako'/>
128 147 </tbody>
129 148 </table>
130 149 </div>
131 150 </div>
132 151 <div class="pagination-wh pagination-left">
133 152 ${c.pagination.render()}
134 153 </div>
135 154 <div id="commit-counter" data-total=${c.total_cs} class="pull-right">
136 155 ${_ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
137 156 </div>
138 157 </div>
139 158
140 159 <script type="text/javascript">
141 160 var cache = {};
142 161 $(function(){
143 162
144 163 // Create links to commit ranges when range checkboxes are selected
145 164 var $commitCheckboxes = $('.commit-range');
146 165 // cache elements
147 166 var $commitRangeMore = $('#rev_range_more');
148 167 var $commitRangeContainer = $('#rev_range_container');
149 168 var $commitRangeClear = $('#rev_range_clear');
169 var $commitRangeAction = $('#rev_range_action');
170 var $commitRangeCombinedUrl = $('#rev_range_combined_url');
171 var $compareFork = $('#compare_fork_button');
150 172
151 173 var checkboxRangeSelector = function(e){
152 174 var selectedCheckboxes = [];
153 175 for (pos in $commitCheckboxes){
154 176 if($commitCheckboxes[pos].checked){
155 177 selectedCheckboxes.push($commitCheckboxes[pos]);
156 178 }
157 179 }
158 180 var open_new_pull_request = $('#open_new_pull_request');
159 181
160 182 if (open_new_pull_request) {
161 183 var selected_changes = selectedCheckboxes.length;
162 184 open_new_pull_request.hide();
163 185 if (selected_changes == 1) {
164 186 open_new_pull_request.html(_gettext('Open new pull request for selected commit'));
165 187 } else {
166 188 open_new_pull_request.html(_gettext('Open new pull request'));
167 189 }
168 190 open_new_pull_request.show();
169 191 }
170 192
171 193 if (selectedCheckboxes.length > 0) {
172 $('#compare_fork_button').hide();
194 $compareFork.hide();
173 195 var commitStart = $(selectedCheckboxes[selectedCheckboxes.length-1]).data();
174
175 196 var revStart = commitStart.commitId;
176 197
177 198 var commitEnd = $(selectedCheckboxes[0]).data();
178 199 var revEnd = commitEnd.commitId;
179 200
180 201 var lbl_start = '{0}'.format(commitStart.commitIdx, commitStart.shortId);
181 202 var lbl_end = '{0}'.format(commitEnd.commitIdx, commitEnd.shortId);
182 203
183 204 var url = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}', 'commit_id': revStart+'...'+revEnd});
184 var link = _gettext('Show commit range {0} ... {1}').format(lbl_start, lbl_end);
205 var urlCombined = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}', 'commit_id': revStart+'...'+revEnd, 'redirect_combined': '1'});
206
207 var link = _gettext('Show commit range {0}<i class="icon-angle-right"></i>{1}').format(lbl_start, lbl_end);
185 208
186 209 if (selectedCheckboxes.length > 1) {
187 210 $commitRangeClear.show();
188 211 $commitRangeMore.hide();
189 212
190 213 $commitRangeContainer
191 214 .attr('href',url)
192 215 .html(link)
193 216 .show();
194 217
218 $commitRangeCombinedUrl.attr('href', urlCombined);
219 $commitRangeAction.show();
195 220
196 221 } else {
197 222 $commitRangeContainer.hide();
223 $commitRangeAction.hide();
198 224 $commitRangeClear.show();
199 225 $commitRangeMore.show();
200 226 }
201 227
202 228 // pull-request link
203 229 if (selectedCheckboxes.length == 1){
204 230 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}', 'commit': revEnd});
205 231 open_new_pull_request.attr('href', _url);
206 232 } else {
207 233 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}'});
208 234 open_new_pull_request.attr('href', _url);
209 235 }
210 236
211 237 } else {
212 238 $commitRangeContainer.hide();
213 239 $commitRangeClear.hide();
214 240 $commitRangeMore.hide();
241 $commitRangeAction.hide();
215 242
216 243 %if c.branch_name:
217 244 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}', 'branch':'${c.branch_name}'});
218 245 open_new_pull_request.attr('href', _url);
219 246 %else:
220 247 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}'});
221 248 open_new_pull_request.attr('href', _url);
222 249 %endif
223 $('#compare_fork_button').show();
250 $compareFork.show();
224 251 }
225 252 };
226 253
227 254 $commitCheckboxes.on('click', checkboxRangeSelector);
228 255
229 256 $commitRangeClear.on('click',function(e) {
230 257 $commitCheckboxes.attr('checked', false);
231 258 checkboxRangeSelector();
232 259 e.preventDefault();
233 260 });
234 261
235 262 // make sure the buttons are consistent when navigate back and forth
236 263 checkboxRangeSelector();
237 264
238 265 var msgs = $('.message');
239 266 // get first element height
240 267 var el = $('#graph_content .container')[0];
241 268 var row_h = el.clientHeight;
242 269 for (var i=0; i < msgs.length; i++) {
243 270 var m = msgs[i];
244 271
245 272 var h = m.clientHeight;
246 273 var pad = $(m).css('padding');
247 274 if (h > row_h) {
248 275 var offset = row_h - (h+12);
249 276 $(m.nextElementSibling).css('display','block');
250 277 $(m.nextElementSibling).css('margin-top',offset+'px');
251 278 }
252 279 }
253 280
254 281 $("#clear_filter").on("click", function() {
255 282 var filter = {'repo_name': '${c.repo_name}'};
256 283 window.location = pyroutes.url('repo_commits', filter);
257 284 });
258 285
259 286 $("#branch_filter").select2({
260 287 'dropdownAutoWidth': true,
261 288 'width': 'resolve',
262 289 'placeholder': "${c.selected_name or _('Branch filter')}",
263 290 containerCssClass: "drop-menu",
264 291 dropdownCssClass: "drop-menu-dropdown",
265 292 query: function(query){
266 293 var key = 'cache';
267 294 var cached = cache[key] ;
268 295 if(cached) {
269 296 var data = {results: []};
270 297 //filter results
271 298 $.each(cached.results, function(){
272 299 var section = this.text;
273 300 var children = [];
274 301 $.each(this.children, function(){
275 302 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
276 303 children.push({'id': this.id, 'text': this.text, 'type': this.type})
277 304 }
278 305 });
279 306 data.results.push({'text': section, 'children': children});
280 307 query.callback({results: data.results});
281 308 });
282 309 }else{
283 310 $.ajax({
284 311 url: pyroutes.url('repo_refs_changelog_data', {'repo_name': '${c.repo_name}'}),
285 312 data: {},
286 313 dataType: 'json',
287 314 type: 'GET',
288 315 success: function(data) {
289 316 cache[key] = data;
290 317 query.callback({results: data.results});
291 318 }
292 319 })
293 320 }
294 321 }
295 322 });
296 323 $('#branch_filter').on('change', function(e){
297 324 var data = $('#branch_filter').select2('data');
298 325 //type: branch_closed
299 326 var selected = data.text;
300 327 var filter = {'repo_name': '${c.repo_name}'};
301 328 if(data.type == 'branch' || data.type == 'branch_closed'){
302 329 filter["branch"] = selected;
303 330 if (data.type == 'branch_closed') {
304 331 filter["evolve"] = '1';
305 332 }
306 333 }
307 334 else if (data.type == 'book'){
308 335 filter["bookmark"] = selected;
309 336 }
310 337 window.location = pyroutes.url('repo_commits', filter);
311 338 });
312 339
313 340 commitsController = new CommitsController();
314 341 % if not c.changelog_for_path:
315 342 commitsController.reloadGraph();
316 343 % endif
317 344
318 345 });
319 346
320 347 </script>
321 348 </div>
322 349 % else:
323 350 ${_('There are no changes yet')}
324 351 % endif
325 352 </div>
326 353 </%def>
General Comments 0
You need to be logged in to leave comments. Login now