Show More
@@ -345,6 +345,16 b' def includeme(config):' | |||
|
345 | 345 | pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete', |
|
346 | 346 | repo_route=True, repo_accepted_types=['hg', 'git']) |
|
347 | 347 | |
|
348 | config.add_route( | |
|
349 | name='pullrequest_comments', | |
|
350 | pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comments', | |
|
351 | repo_route=True) | |
|
352 | ||
|
353 | config.add_route( | |
|
354 | name='pullrequest_todos', | |
|
355 | pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos', | |
|
356 | repo_route=True) | |
|
357 | ||
|
348 | 358 | # Artifacts, (EE feature) |
|
349 | 359 | config.add_route( |
|
350 | 360 | name='repo_artifacts_list', |
@@ -87,6 +87,7 b' class RepoCommitsView(RepoAppView):' | |||
|
87 | 87 | diff_limit = c.visual.cut_off_limit_diff |
|
88 | 88 | file_limit = c.visual.cut_off_limit_file |
|
89 | 89 | |
|
90 | ||
|
90 | 91 | # get ranges of commit ids if preset |
|
91 | 92 | commit_range = commit_id_range.split('...')[:2] |
|
92 | 93 | |
@@ -226,6 +227,7 b' class RepoCommitsView(RepoAppView):' | |||
|
226 | 227 | |
|
227 | 228 | # sort comments by how they were generated |
|
228 | 229 | c.comments = sorted(c.comments, key=lambda x: x.comment_id) |
|
230 | c.at_version_num = None | |
|
229 | 231 | |
|
230 | 232 | if len(c.commit_ranges) == 1: |
|
231 | 233 | c.commit = c.commit_ranges[0] |
@@ -265,6 +265,36 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
265 | 265 | |
|
266 | 266 | return diffset |
|
267 | 267 | |
|
268 | def register_comments_vars(self, c, pull_request, versions): | |
|
269 | comments_model = CommentsModel() | |
|
270 | ||
|
271 | # GENERAL COMMENTS with versions # | |
|
272 | q = comments_model._all_general_comments_of_pull_request(pull_request) | |
|
273 | q = q.order_by(ChangesetComment.comment_id.asc()) | |
|
274 | general_comments = q | |
|
275 | ||
|
276 | # pick comments we want to render at current version | |
|
277 | c.comment_versions = comments_model.aggregate_comments( | |
|
278 | general_comments, versions, c.at_version_num) | |
|
279 | ||
|
280 | # INLINE COMMENTS with versions # | |
|
281 | q = comments_model._all_inline_comments_of_pull_request(pull_request) | |
|
282 | q = q.order_by(ChangesetComment.comment_id.asc()) | |
|
283 | inline_comments = q | |
|
284 | ||
|
285 | c.inline_versions = comments_model.aggregate_comments( | |
|
286 | inline_comments, versions, c.at_version_num, inline=True) | |
|
287 | ||
|
288 | # Comments inline+general | |
|
289 | if c.at_version: | |
|
290 | c.inline_comments_flat = c.inline_versions[c.at_version_num]['display'] | |
|
291 | c.comments = c.comment_versions[c.at_version_num]['display'] | |
|
292 | else: | |
|
293 | c.inline_comments_flat = c.inline_versions[c.at_version_num]['until'] | |
|
294 | c.comments = c.comment_versions[c.at_version_num]['until'] | |
|
295 | ||
|
296 | return general_comments, inline_comments | |
|
297 | ||
|
268 | 298 | @LoginRequired() |
|
269 | 299 | @HasRepoPermissionAnyDecorator( |
|
270 | 300 | 'repository.read', 'repository.write', 'repository.admin') |
@@ -280,6 +310,8 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
280 | 310 | pull_request_id = pull_request.pull_request_id |
|
281 | 311 | |
|
282 | 312 | c.state_progressing = pull_request.is_state_changing() |
|
313 | c.pr_broadcast_channel = '/repo${}$/pr/{}'.format( | |
|
314 | pull_request.target_repo.repo_name, pull_request.pull_request_id) | |
|
283 | 315 | |
|
284 | 316 | _new_state = { |
|
285 | 317 | 'created': PullRequest.STATE_CREATED, |
@@ -300,22 +332,23 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
300 | 332 | from_version = self.request.GET.get('from_version') or version |
|
301 | 333 | merge_checks = self.request.GET.get('merge_checks') |
|
302 | 334 | c.fulldiff = str2bool(self.request.GET.get('fulldiff')) |
|
335 | force_refresh = str2bool(self.request.GET.get('force_refresh')) | |
|
336 | c.range_diff_on = self.request.GET.get('range-diff') == "1" | |
|
303 | 337 | |
|
304 | 338 | # fetch global flags of ignore ws or context lines |
|
305 | 339 | diff_context = diffs.get_diff_context(self.request) |
|
306 | 340 | hide_whitespace_changes = diffs.get_diff_whitespace_flag(self.request) |
|
307 | 341 | |
|
308 | force_refresh = str2bool(self.request.GET.get('force_refresh')) | |
|
309 | ||
|
310 | 342 | (pull_request_latest, |
|
311 | 343 | pull_request_at_ver, |
|
312 | 344 | pull_request_display_obj, |
|
313 | 345 | at_version) = PullRequestModel().get_pr_version( |
|
314 | 346 | pull_request_id, version=version) |
|
347 | ||
|
315 | 348 | pr_closed = pull_request_latest.is_closed() |
|
316 | 349 | |
|
317 | 350 | if pr_closed and (version or from_version): |
|
318 | # not allow to browse versions | |
|
351 | # not allow to browse versions for closed PR | |
|
319 | 352 | raise HTTPFound(h.route_path( |
|
320 | 353 | 'pullrequest_show', repo_name=self.db_repo_name, |
|
321 | 354 | pull_request_id=pull_request_id)) |
@@ -323,13 +356,13 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
323 | 356 | versions = pull_request_display_obj.versions() |
|
324 | 357 | # used to store per-commit range diffs |
|
325 | 358 | c.changes = collections.OrderedDict() |
|
326 | c.range_diff_on = self.request.GET.get('range-diff') == "1" | |
|
327 | 359 | |
|
328 | 360 | c.at_version = at_version |
|
329 | 361 | c.at_version_num = (at_version |
|
330 |
if at_version and at_version != |
|
|
362 | if at_version and at_version != PullRequest.LATEST_VER | |
|
331 | 363 | else None) |
|
332 | c.at_version_pos = ChangesetComment.get_index_from_version( | |
|
364 | ||
|
365 | c.at_version_index = ChangesetComment.get_index_from_version( | |
|
333 | 366 | c.at_version_num, versions) |
|
334 | 367 | |
|
335 | 368 | (prev_pull_request_latest, |
@@ -340,9 +373,9 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
340 | 373 | |
|
341 | 374 | c.from_version = prev_at_version |
|
342 | 375 | c.from_version_num = (prev_at_version |
|
343 |
if prev_at_version and prev_at_version != |
|
|
376 | if prev_at_version and prev_at_version != PullRequest.LATEST_VER | |
|
344 | 377 | else None) |
|
345 |
c.from_version_ |
|
|
378 | c.from_version_index = ChangesetComment.get_index_from_version( | |
|
346 | 379 | c.from_version_num, versions) |
|
347 | 380 | |
|
348 | 381 | # define if we're in COMPARE mode or VIEW at version mode |
@@ -355,14 +388,17 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
355 | 388 | self.db_repo_name, pull_request_at_ver.target_repo.repo_name) |
|
356 | 389 | raise HTTPNotFound() |
|
357 | 390 | |
|
358 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( | |
|
359 | pull_request_at_ver) | |
|
391 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url(pull_request_at_ver) | |
|
360 | 392 | |
|
361 | 393 | c.pull_request = pull_request_display_obj |
|
362 | 394 | c.renderer = pull_request_at_ver.description_renderer or c.renderer |
|
363 | 395 | c.pull_request_latest = pull_request_latest |
|
364 | 396 | |
|
365 | if compare or (at_version and not at_version == 'latest'): | |
|
397 | # inject latest version | |
|
398 | latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest) | |
|
399 | c.versions = versions + [latest_ver] | |
|
400 | ||
|
401 | if compare or (at_version and not at_version == PullRequest.LATEST_VER): | |
|
366 | 402 | c.allowed_to_change_status = False |
|
367 | 403 | c.allowed_to_update = False |
|
368 | 404 | c.allowed_to_merge = False |
@@ -391,12 +427,9 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
391 | 427 | 'rules' in pull_request_latest.reviewer_data: |
|
392 | 428 | rules = pull_request_latest.reviewer_data['rules'] or {} |
|
393 | 429 | try: |
|
394 | c.forbid_adding_reviewers = rules.get( | |
|
395 | 'forbid_adding_reviewers') | |
|
396 | c.forbid_author_to_review = rules.get( | |
|
397 | 'forbid_author_to_review') | |
|
398 | c.forbid_commit_author_to_review = rules.get( | |
|
399 | 'forbid_commit_author_to_review') | |
|
430 | c.forbid_adding_reviewers = rules.get('forbid_adding_reviewers') | |
|
431 | c.forbid_author_to_review = rules.get('forbid_author_to_review') | |
|
432 | c.forbid_commit_author_to_review = rules.get('forbid_commit_author_to_review') | |
|
400 | 433 | except Exception: |
|
401 | 434 | pass |
|
402 | 435 | |
@@ -421,41 +454,37 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
421 | 454 | 'rhodecode:templates/pullrequests/pullrequest_merge_checks.mako' |
|
422 | 455 | return self._get_template_context(c) |
|
423 | 456 | |
|
424 | comments_model = CommentsModel() | |
|
457 | c.allowed_reviewers = [obj.user_id for obj in pull_request.reviewers if obj.user] | |
|
425 | 458 | |
|
426 | 459 | # reviewers and statuses |
|
427 |
c.pull_request_reviewers = |
|
|
428 | allowed_reviewers = [x[0].user_id for x in c.pull_request_reviewers] | |
|
460 | c.pull_request_default_reviewers_data_json = json.dumps(pull_request.reviewer_data) | |
|
461 | c.pull_request_set_reviewers_data_json = collections.OrderedDict({'reviewers': []}) | |
|
429 | 462 | |
|
430 | # GENERAL COMMENTS with versions # | |
|
431 | q = comments_model._all_general_comments_of_pull_request(pull_request_latest) | |
|
432 | q = q.order_by(ChangesetComment.comment_id.asc()) | |
|
433 | general_comments = q | |
|
463 | for review_obj, member, reasons, mandatory, status in pull_request_at_ver.reviewers_statuses(): | |
|
464 | member_reviewer = h.reviewer_as_json( | |
|
465 | member, reasons=reasons, mandatory=mandatory, | |
|
466 | user_group=review_obj.rule_user_group_data() | |
|
467 | ) | |
|
434 | 468 | |
|
435 | # pick comments we want to render at current version | |
|
436 | c.comment_versions = comments_model.aggregate_comments( | |
|
437 | general_comments, versions, c.at_version_num) | |
|
438 | c.comments = c.comment_versions[c.at_version_num]['until'] | |
|
469 | current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED | |
|
470 | member_reviewer['review_status'] = current_review_status | |
|
471 | member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status) | |
|
472 | member_reviewer['allowed_to_update'] = c.allowed_to_update | |
|
473 | c.pull_request_set_reviewers_data_json['reviewers'].append(member_reviewer) | |
|
439 | 474 | |
|
440 | # INLINE COMMENTS with versions # | |
|
441 | q = comments_model._all_inline_comments_of_pull_request(pull_request_latest) | |
|
442 | q = q.order_by(ChangesetComment.comment_id.asc()) | |
|
443 | inline_comments = q | |
|
475 | c.pull_request_set_reviewers_data_json = json.dumps(c.pull_request_set_reviewers_data_json) | |
|
476 | ||
|
477 | ||
|
444 | 478 | |
|
445 | c.inline_versions = comments_model.aggregate_comments( | |
|
446 | inline_comments, versions, c.at_version_num, inline=True) | |
|
479 | ||
|
480 | general_comments, inline_comments = \ | |
|
481 | self.register_comments_vars(c, pull_request_latest, versions) | |
|
447 | 482 | |
|
448 | 483 | # TODOs |
|
449 | 484 | c.unresolved_comments = CommentsModel() \ |
|
450 | .get_pull_request_unresolved_todos(pull_request) | |
|
485 | .get_pull_request_unresolved_todos(pull_request_latest) | |
|
451 | 486 | c.resolved_comments = CommentsModel() \ |
|
452 | .get_pull_request_resolved_todos(pull_request) | |
|
453 | ||
|
454 | # inject latest version | |
|
455 | latest_ver = PullRequest.get_pr_display_object( | |
|
456 | pull_request_latest, pull_request_latest) | |
|
457 | ||
|
458 | c.versions = versions + [latest_ver] | |
|
487 | .get_pull_request_resolved_todos(pull_request_latest) | |
|
459 | 488 | |
|
460 | 489 | # if we use version, then do not show later comments |
|
461 | 490 | # than current version |
@@ -522,8 +551,8 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
522 | 551 | |
|
523 | 552 | # empty version means latest, so we keep this to prevent |
|
524 | 553 | # double caching |
|
525 |
version_normalized = version or |
|
|
526 |
from_version_normalized = from_version or |
|
|
554 | version_normalized = version or PullRequest.LATEST_VER | |
|
555 | from_version_normalized = from_version or PullRequest.LATEST_VER | |
|
527 | 556 | |
|
528 | 557 | cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(target_repo) |
|
529 | 558 | cache_file_path = diff_cache_exist( |
@@ -615,7 +644,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
615 | 644 | diff_limit, file_limit, c.fulldiff, |
|
616 | 645 | hide_whitespace_changes, diff_context, |
|
617 | 646 | use_ancestor=use_ancestor |
|
618 | ) | |
|
647 | ) | |
|
619 | 648 | |
|
620 | 649 | # save cached diff |
|
621 | 650 | if caching_enabled: |
@@ -719,7 +748,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
719 | 748 | |
|
720 | 749 | # current user review statuses for each version |
|
721 | 750 | c.review_versions = {} |
|
722 | if self._rhodecode_user.user_id in allowed_reviewers: | |
|
751 | if self._rhodecode_user.user_id in c.allowed_reviewers: | |
|
723 | 752 | for co in general_comments: |
|
724 | 753 | if co.author.user_id == self._rhodecode_user.user_id: |
|
725 | 754 | status = co.status_change |
@@ -939,6 +968,83 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
939 | 968 | @NotAnonymous() |
|
940 | 969 | @HasRepoPermissionAnyDecorator( |
|
941 | 970 | 'repository.read', 'repository.write', 'repository.admin') |
|
971 | @view_config( | |
|
972 | route_name='pullrequest_comments', request_method='POST', | |
|
973 | renderer='string', xhr=True) | |
|
974 | def pullrequest_comments(self): | |
|
975 | self.load_default_context() | |
|
976 | ||
|
977 | pull_request = PullRequest.get_or_404( | |
|
978 | self.request.matchdict['pull_request_id']) | |
|
979 | pull_request_id = pull_request.pull_request_id | |
|
980 | version = self.request.GET.get('version') | |
|
981 | ||
|
982 | _render = self.request.get_partial_renderer( | |
|
983 | 'rhodecode:templates/pullrequests/pullrequest_show.mako') | |
|
984 | c = _render.get_call_context() | |
|
985 | ||
|
986 | (pull_request_latest, | |
|
987 | pull_request_at_ver, | |
|
988 | pull_request_display_obj, | |
|
989 | at_version) = PullRequestModel().get_pr_version( | |
|
990 | pull_request_id, version=version) | |
|
991 | versions = pull_request_display_obj.versions() | |
|
992 | latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest) | |
|
993 | c.versions = versions + [latest_ver] | |
|
994 | ||
|
995 | c.at_version = at_version | |
|
996 | c.at_version_num = (at_version | |
|
997 | if at_version and at_version != PullRequest.LATEST_VER | |
|
998 | else None) | |
|
999 | ||
|
1000 | self.register_comments_vars(c, pull_request_latest, versions) | |
|
1001 | all_comments = c.inline_comments_flat + c.comments | |
|
1002 | return _render('comments_table', all_comments, len(all_comments)) | |
|
1003 | ||
|
1004 | @LoginRequired() | |
|
1005 | @NotAnonymous() | |
|
1006 | @HasRepoPermissionAnyDecorator( | |
|
1007 | 'repository.read', 'repository.write', 'repository.admin') | |
|
1008 | @view_config( | |
|
1009 | route_name='pullrequest_todos', request_method='POST', | |
|
1010 | renderer='string', xhr=True) | |
|
1011 | def pullrequest_todos(self): | |
|
1012 | self.load_default_context() | |
|
1013 | ||
|
1014 | pull_request = PullRequest.get_or_404( | |
|
1015 | self.request.matchdict['pull_request_id']) | |
|
1016 | pull_request_id = pull_request.pull_request_id | |
|
1017 | version = self.request.GET.get('version') | |
|
1018 | ||
|
1019 | _render = self.request.get_partial_renderer( | |
|
1020 | 'rhodecode:templates/pullrequests/pullrequest_show.mako') | |
|
1021 | c = _render.get_call_context() | |
|
1022 | (pull_request_latest, | |
|
1023 | pull_request_at_ver, | |
|
1024 | pull_request_display_obj, | |
|
1025 | at_version) = PullRequestModel().get_pr_version( | |
|
1026 | pull_request_id, version=version) | |
|
1027 | versions = pull_request_display_obj.versions() | |
|
1028 | latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest) | |
|
1029 | c.versions = versions + [latest_ver] | |
|
1030 | ||
|
1031 | c.at_version = at_version | |
|
1032 | c.at_version_num = (at_version | |
|
1033 | if at_version and at_version != PullRequest.LATEST_VER | |
|
1034 | else None) | |
|
1035 | ||
|
1036 | c.unresolved_comments = CommentsModel() \ | |
|
1037 | .get_pull_request_unresolved_todos(pull_request) | |
|
1038 | c.resolved_comments = CommentsModel() \ | |
|
1039 | .get_pull_request_resolved_todos(pull_request) | |
|
1040 | ||
|
1041 | all_comments = c.unresolved_comments + c.resolved_comments | |
|
1042 | return _render('comments_table', all_comments, len(c.unresolved_comments), todo_comments=True) | |
|
1043 | ||
|
1044 | @LoginRequired() | |
|
1045 | @NotAnonymous() | |
|
1046 | @HasRepoPermissionAnyDecorator( | |
|
1047 | 'repository.read', 'repository.write', 'repository.admin') | |
|
942 | 1048 | @CSRFRequired() |
|
943 | 1049 | @view_config( |
|
944 | 1050 | route_name='pullrequest_create', request_method='POST', |
@@ -1100,7 +1206,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1100 | 1206 | self.request.matchdict['pull_request_id']) |
|
1101 | 1207 | _ = self.request.translate |
|
1102 | 1208 | |
|
1103 | self.load_default_context() | |
|
1209 | c = self.load_default_context() | |
|
1104 | 1210 | redirect_url = None |
|
1105 | 1211 | |
|
1106 | 1212 | if pull_request.is_closed(): |
@@ -1111,6 +1217,8 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1111 | 1217 | 'redirect_url': redirect_url} |
|
1112 | 1218 | |
|
1113 | 1219 | is_state_changing = pull_request.is_state_changing() |
|
1220 | c.pr_broadcast_channel = '/repo${}$/pr/{}'.format( | |
|
1221 | pull_request.target_repo.repo_name, pull_request.pull_request_id) | |
|
1114 | 1222 | |
|
1115 | 1223 | # only owner or admin can update it |
|
1116 | 1224 | allowed_to_update = PullRequestModel().check_user_update( |
@@ -1134,7 +1242,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1134 | 1242 | return {'response': True, |
|
1135 | 1243 | 'redirect_url': redirect_url} |
|
1136 | 1244 | |
|
1137 | self._update_commits(pull_request) | |
|
1245 | self._update_commits(c, pull_request) | |
|
1138 | 1246 | if force_refresh: |
|
1139 | 1247 | redirect_url = h.route_path( |
|
1140 | 1248 | 'pullrequest_show', repo_name=self.db_repo_name, |
@@ -1170,7 +1278,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1170 | 1278 | h.flash(msg, category='success') |
|
1171 | 1279 | return |
|
1172 | 1280 | |
|
1173 | def _update_commits(self, pull_request): | |
|
1281 | def _update_commits(self, c, pull_request): | |
|
1174 | 1282 | _ = self.request.translate |
|
1175 | 1283 | |
|
1176 | 1284 | with pull_request.set_state(PullRequest.STATE_UPDATING): |
@@ -1198,13 +1306,18 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1198 | 1306 | change_source=changed) |
|
1199 | 1307 | h.flash(msg, category='success') |
|
1200 | 1308 | |
|
1201 | channel = '/repo${}$/pr/{}'.format( | |
|
1202 | pull_request.target_repo.repo_name, pull_request.pull_request_id) | |
|
1203 | 1309 | message = msg + ( |
|
1204 | 1310 | ' - <a onclick="window.location.reload()">' |
|
1205 | 1311 | '<strong>{}</strong></a>'.format(_('Reload page'))) |
|
1312 | ||
|
1313 | message_obj = { | |
|
1314 | 'message': message, | |
|
1315 | 'level': 'success', | |
|
1316 | 'topic': '/notifications' | |
|
1317 | } | |
|
1318 | ||
|
1206 | 1319 | channelstream.post_message( |
|
1207 | channel, message, self._rhodecode_user.username, | |
|
1320 | c.pr_broadcast_channel, message_obj, self._rhodecode_user.username, | |
|
1208 | 1321 | registry=self.request.registry) |
|
1209 | 1322 | else: |
|
1210 | 1323 | msg = PullRequestModel.UPDATE_STATUS_MESSAGES[resp.reason] |
@@ -1474,6 +1587,7 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1474 | 1587 | } |
|
1475 | 1588 | if comment: |
|
1476 | 1589 | c.co = comment |
|
1590 | c.at_version_num = None | |
|
1477 | 1591 | rendered_comment = render( |
|
1478 | 1592 | 'rhodecode:templates/changeset/changeset_comment_block.mako', |
|
1479 | 1593 | self._get_template_context(c), self.request) |
@@ -810,8 +810,7 b' import tzlocal' | |||
|
810 | 810 | local_timezone = tzlocal.get_localzone() |
|
811 | 811 | |
|
812 | 812 | |
|
813 |
def |
|
|
814 | title = value or format_date(datetime_iso) | |
|
813 | def get_timezone(datetime_iso, time_is_local=False): | |
|
815 | 814 | tzinfo = '+00:00' |
|
816 | 815 | |
|
817 | 816 | # detect if we have a timezone info, otherwise, add it |
@@ -822,6 +821,12 b' def age_component(datetime_iso, value=No' | |||
|
822 | 821 | timezone = force_timezone or local_timezone |
|
823 | 822 | offset = timezone.localize(datetime_iso).strftime('%z') |
|
824 | 823 | tzinfo = '{}:{}'.format(offset[:-2], offset[-2:]) |
|
824 | return tzinfo | |
|
825 | ||
|
826 | ||
|
827 | def age_component(datetime_iso, value=None, time_is_local=False, tooltip=True): | |
|
828 | title = value or format_date(datetime_iso) | |
|
829 | tzinfo = get_timezone(datetime_iso, time_is_local=time_is_local) | |
|
825 | 830 | |
|
826 | 831 | return literal( |
|
827 | 832 | '<time class="timeago {cls}" title="{tt_title}" datetime="{dt}{tzinfo}">{title}</time>'.format( |
@@ -1650,17 +1655,18 b' def get_active_pattern_entries(repo_name' | |||
|
1650 | 1655 | |
|
1651 | 1656 | pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)') |
|
1652 | 1657 | |
|
1658 | allowed_link_formats = [ | |
|
1659 | 'html', 'rst', 'markdown', 'html+hovercard', 'rst+hovercard', 'markdown+hovercard'] | |
|
1660 | ||
|
1653 | 1661 | |
|
1654 | 1662 | def process_patterns(text_string, repo_name, link_format='html', active_entries=None): |
|
1655 | 1663 | |
|
1656 | allowed_formats = ['html', 'rst', 'markdown', | |
|
1657 | 'html+hovercard', 'rst+hovercard', 'markdown+hovercard'] | |
|
1658 | if link_format not in allowed_formats: | |
|
1664 | if link_format not in allowed_link_formats: | |
|
1659 | 1665 | raise ValueError('Link format can be only one of:{} got {}'.format( |
|
1660 | allowed_formats, link_format)) | |
|
1666 | allowed_link_formats, link_format)) | |
|
1661 | 1667 | |
|
1662 | 1668 | if active_entries is None: |
|
1663 | log.debug('Fetch active patterns for repo: %s', repo_name) | |
|
1669 | log.debug('Fetch active issue tracker patterns for repo: %s', repo_name) | |
|
1664 | 1670 | active_entries = get_active_pattern_entries(repo_name) |
|
1665 | 1671 | |
|
1666 | 1672 | issues_data = [] |
@@ -1718,7 +1724,8 b' def process_patterns(text_string, repo_n' | |||
|
1718 | 1724 | return new_text, issues_data |
|
1719 | 1725 | |
|
1720 | 1726 | |
|
1721 |
def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None |
|
|
1727 | def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None, | |
|
1728 | issues_container=None): | |
|
1722 | 1729 | """ |
|
1723 | 1730 | Parses given text message and makes proper links. |
|
1724 | 1731 | issues are linked to given issue-server, and rest is a commit link |
@@ -1741,6 +1748,9 b' def urlify_commit_message(commit_text, r' | |||
|
1741 | 1748 | new_text, issues = process_patterns(new_text, repository or '', |
|
1742 | 1749 | active_entries=active_pattern_entries) |
|
1743 | 1750 | |
|
1751 | if issues_container is not None: | |
|
1752 | issues_container.extend(issues) | |
|
1753 | ||
|
1744 | 1754 | return literal(new_text) |
|
1745 | 1755 | |
|
1746 | 1756 | |
@@ -1781,7 +1791,7 b' def renderer_from_filename(filename, exc' | |||
|
1781 | 1791 | |
|
1782 | 1792 | |
|
1783 | 1793 | def render(source, renderer='rst', mentions=False, relative_urls=None, |
|
1784 | repo_name=None, active_pattern_entries=None): | |
|
1794 | repo_name=None, active_pattern_entries=None, issues_container=None): | |
|
1785 | 1795 | |
|
1786 | 1796 | def maybe_convert_relative_links(html_source): |
|
1787 | 1797 | if relative_urls: |
@@ -1798,6 +1808,8 b" def render(source, renderer='rst', menti" | |||
|
1798 | 1808 | source, issues = process_patterns( |
|
1799 | 1809 | source, repo_name, link_format='rst', |
|
1800 | 1810 | active_entries=active_pattern_entries) |
|
1811 | if issues_container is not None: | |
|
1812 | issues_container.extend(issues) | |
|
1801 | 1813 | |
|
1802 | 1814 | return literal( |
|
1803 | 1815 | '<div class="rst-block">%s</div>' % |
@@ -1810,6 +1822,8 b" def render(source, renderer='rst', menti" | |||
|
1810 | 1822 | source, issues = process_patterns( |
|
1811 | 1823 | source, repo_name, link_format='markdown', |
|
1812 | 1824 | active_entries=active_pattern_entries) |
|
1825 | if issues_container is not None: | |
|
1826 | issues_container.extend(issues) | |
|
1813 | 1827 | |
|
1814 | 1828 | return literal( |
|
1815 | 1829 | '<div class="markdown-block">%s</div>' % |
@@ -91,8 +91,7 b' class CommentsModel(BaseModel):' | |||
|
91 | 91 | # group by versions, and count until, and display objects |
|
92 | 92 | |
|
93 | 93 | comment_groups = collections.defaultdict(list) |
|
94 | [comment_groups[ | |
|
95 | _co.pull_request_version_id].append(_co) for _co in comments] | |
|
94 | [comment_groups[_co.pull_request_version_id].append(_co) for _co in comments] | |
|
96 | 95 | |
|
97 | 96 | def yield_comments(pos): |
|
98 | 97 | for co in comment_groups[pos]: |
@@ -456,38 +455,54 b' class CommentsModel(BaseModel):' | |||
|
456 | 455 | else: |
|
457 | 456 | action = 'repo.commit.comment.create' |
|
458 | 457 | |
|
458 | comment_id = comment.comment_id | |
|
459 | 459 | comment_data = comment.get_api_data() |
|
460 | ||
|
460 | 461 | self._log_audit_action( |
|
461 | 462 | action, {'data': comment_data}, auth_user, comment) |
|
462 | 463 | |
|
463 | msg_url = '' | |
|
464 | 464 | channel = None |
|
465 | 465 | if commit_obj: |
|
466 | msg_url = commit_comment_url | |
|
467 | 466 | repo_name = repo.repo_name |
|
468 | 467 | channel = u'/repo${}$/commit/{}'.format( |
|
469 | 468 | repo_name, |
|
470 | 469 | commit_obj.raw_id |
|
471 | 470 | ) |
|
472 | 471 | elif pull_request_obj: |
|
473 | msg_url = pr_comment_url | |
|
474 | 472 | repo_name = pr_target_repo.repo_name |
|
475 | 473 | channel = u'/repo${}$/pr/{}'.format( |
|
476 | 474 | repo_name, |
|
477 | pull_request_id | |
|
475 | pull_request_obj.pull_request_id | |
|
478 | 476 | ) |
|
479 | 477 | |
|
480 | message = '<strong>{}</strong> {} - ' \ | |
|
481 | '<a onclick="window.location=\'{}\';' \ | |
|
482 | 'window.location.reload()">' \ | |
|
483 | '<strong>{}</strong></a>' | |
|
484 | message = message.format( | |
|
485 |
|
|
|
486 | _('Show it now')) | |
|
478 | if channel: | |
|
479 | username = user.username | |
|
480 | message = '<strong>{}</strong> {} #{}, {}' | |
|
481 | message = message.format( | |
|
482 | username, | |
|
483 | _('posted a new comment'), | |
|
484 | comment_id, | |
|
485 | _('Refresh the page to see new comments.')) | |
|
487 | 486 | |
|
488 | channelstream.post_message( | |
|
489 | channel, message, user.username, | |
|
490 | registry=get_current_registry()) | |
|
487 | message_obj = { | |
|
488 | 'message': message, | |
|
489 | 'level': 'success', | |
|
490 | 'topic': '/notifications' | |
|
491 | } | |
|
492 | ||
|
493 | channelstream.post_message( | |
|
494 | channel, message_obj, user.username, | |
|
495 | registry=get_current_registry()) | |
|
496 | ||
|
497 | message_obj = { | |
|
498 | 'message': None, | |
|
499 | 'user': username, | |
|
500 | 'comment_id': comment_id, | |
|
501 | 'topic': '/comment' | |
|
502 | } | |
|
503 | channelstream.post_message( | |
|
504 | channel, message_obj, user.username, | |
|
505 | registry=get_current_registry()) | |
|
491 | 506 | |
|
492 | 507 | return comment |
|
493 | 508 | |
@@ -642,15 +657,15 b' class CommentsModel(BaseModel):' | |||
|
642 | 657 | return self._group_comments_by_path_and_line_number(q) |
|
643 | 658 | |
|
644 | 659 | def get_inline_comments_as_list(self, inline_comments, skip_outdated=True, |
|
645 | version=None): | |
|
646 |
inline_c |
|
|
660 | version=None): | |
|
661 | inline_comms = [] | |
|
647 | 662 | for fname, per_line_comments in inline_comments.iteritems(): |
|
648 | 663 | for lno, comments in per_line_comments.iteritems(): |
|
649 | 664 | for comm in comments: |
|
650 | 665 | if not comm.outdated_at_version(version) and skip_outdated: |
|
651 |
inline_c |
|
|
666 | inline_comms.append(comm) | |
|
652 | 667 | |
|
653 |
return inline_c |
|
|
668 | return inline_comms | |
|
654 | 669 | |
|
655 | 670 | def get_outdated_comments(self, repo_id, pull_request): |
|
656 | 671 | # TODO: johbo: Remove `repo_id`, it is not needed to find the comments |
@@ -3821,16 +3821,35 b' class ChangesetComment(Base, BaseModel):' | |||
|
3821 | 3821 | """ |
|
3822 | 3822 | Checks if comment is outdated for given pull request version |
|
3823 | 3823 | """ |
|
3824 | return self.outdated and self.pull_request_version_id != version | |
|
3824 | def version_check(): | |
|
3825 | return self.pull_request_version_id and self.pull_request_version_id != version | |
|
3826 | ||
|
3827 | if self.is_inline: | |
|
3828 | return self.outdated and version_check() | |
|
3829 | else: | |
|
3830 | # general comments don't have .outdated set, also latest don't have a version | |
|
3831 | return version_check() | |
|
3832 | ||
|
3833 | def outdated_at_version_js(self, version): | |
|
3834 | """ | |
|
3835 | Checks if comment is outdated for given pull request version | |
|
3836 | """ | |
|
3837 | return json.dumps(self.outdated_at_version(version)) | |
|
3825 | 3838 | |
|
3826 | 3839 | def older_than_version(self, version): |
|
3827 | 3840 | """ |
|
3828 | 3841 | Checks if comment is made from previous version than given |
|
3829 | 3842 | """ |
|
3830 | 3843 | if version is None: |
|
3831 |
return self.pull_request_version |
|
|
3832 | ||
|
3833 |
return self.pull_request_version |
|
|
3844 | return self.pull_request_version != version | |
|
3845 | ||
|
3846 | return self.pull_request_version < version | |
|
3847 | ||
|
3848 | def older_than_version_js(self, version): | |
|
3849 | """ | |
|
3850 | Checks if comment is made from previous version than given | |
|
3851 | """ | |
|
3852 | return json.dumps(self.older_than_version(version)) | |
|
3834 | 3853 | |
|
3835 | 3854 | @property |
|
3836 | 3855 | def commit_id(self): |
@@ -4327,6 +4346,7 b' class PullRequest(Base, _PullRequestBase' | |||
|
4327 | 4346 | __table_args__ = ( |
|
4328 | 4347 | base_table_args, |
|
4329 | 4348 | ) |
|
4349 | LATEST_VER = 'latest' | |
|
4330 | 4350 | |
|
4331 | 4351 | pull_request_id = Column( |
|
4332 | 4352 | 'pull_request_id', Integer(), nullable=False, primary_key=True) |
@@ -4385,6 +4405,10 b' class PullRequest(Base, _PullRequestBase' | |||
|
4385 | 4405 | def pull_request_version_id(self): |
|
4386 | 4406 | return getattr(pull_request_obj, 'pull_request_version_id', None) |
|
4387 | 4407 | |
|
4408 | @property | |
|
4409 | def pull_request_last_version(self): | |
|
4410 | return pull_request_obj.pull_request_last_version | |
|
4411 | ||
|
4388 | 4412 | attrs = StrictAttributeDict(pull_request_obj.get_api_data(with_merge_state=False)) |
|
4389 | 4413 | |
|
4390 | 4414 | attrs.author = StrictAttributeDict( |
@@ -4449,6 +4473,10 b' class PullRequest(Base, _PullRequestBase' | |||
|
4449 | 4473 | """ |
|
4450 | 4474 | return self.versions.count() + 1 |
|
4451 | 4475 | |
|
4476 | @property | |
|
4477 | def pull_request_last_version(self): | |
|
4478 | return self.versions_count | |
|
4479 | ||
|
4452 | 4480 | |
|
4453 | 4481 | class PullRequestVersion(Base, _PullRequestBase): |
|
4454 | 4482 | __tablename__ = 'pull_request_versions' |
@@ -240,14 +240,14 b' div.markdown-block ol {' | |||
|
240 | 240 | div.markdown-block ul.checkbox li, |
|
241 | 241 | div.markdown-block ol.checkbox li { |
|
242 | 242 | list-style: none !important; |
|
243 |
margin: |
|
|
243 | margin: 0px !important; | |
|
244 | 244 | padding: 0 !important; |
|
245 | 245 | } |
|
246 | 246 | |
|
247 | 247 | div.markdown-block ul li, |
|
248 | 248 | div.markdown-block ol li { |
|
249 | 249 | list-style: disc !important; |
|
250 |
margin: |
|
|
250 | margin: 0px !important; | |
|
251 | 251 | padding: 0 !important; |
|
252 | 252 | } |
|
253 | 253 |
@@ -1510,18 +1510,14 b' table.integrations {' | |||
|
1510 | 1510 | min-height: 55px; |
|
1511 | 1511 | } |
|
1512 | 1512 | |
|
1513 | .reviewers_member { | |
|
1514 | width: 100%; | |
|
1515 | overflow: auto; | |
|
1516 | } | |
|
1517 | 1513 | .reviewer_reason { |
|
1518 | 1514 | padding-left: 20px; |
|
1519 | 1515 | line-height: 1.5em; |
|
1520 | 1516 | } |
|
1521 | 1517 | .reviewer_status { |
|
1522 | 1518 | display: inline-block; |
|
1523 |
width: 2 |
|
|
1524 |
min-width: 2 |
|
|
1519 | width: 20px; | |
|
1520 | min-width: 20px; | |
|
1525 | 1521 | height: 1.2em; |
|
1526 | 1522 | line-height: 1em; |
|
1527 | 1523 | } |
@@ -1544,23 +1540,17 b' table.integrations {' | |||
|
1544 | 1540 | } |
|
1545 | 1541 | |
|
1546 | 1542 | .reviewer_member_mandatory { |
|
1547 | position: absolute; | |
|
1548 | left: 15px; | |
|
1549 | top: 8px; | |
|
1550 | 1543 | width: 16px; |
|
1551 | 1544 | font-size: 11px; |
|
1552 | 1545 | margin: 0; |
|
1553 | 1546 | padding: 0; |
|
1554 | 1547 | color: black; |
|
1548 | opacity: 0.4; | |
|
1555 | 1549 | } |
|
1556 | 1550 | |
|
1557 | 1551 | .reviewer_member_mandatory_remove, |
|
1558 | 1552 | .reviewer_member_remove { |
|
1559 | position: absolute; | |
|
1560 | right: 0; | |
|
1561 | top: 0; | |
|
1562 | 1553 | width: 16px; |
|
1563 | margin-bottom: 10px; | |
|
1564 | 1554 | padding: 0; |
|
1565 | 1555 | color: black; |
|
1566 | 1556 | } |
@@ -1617,7 +1607,8 b' table.integrations {' | |||
|
1617 | 1607 | .td-todo-number { |
|
1618 | 1608 | text-align: left; |
|
1619 | 1609 | white-space: nowrap; |
|
1620 |
width: 1 |
|
|
1610 | width: 1%; | |
|
1611 | padding-right: 2px; | |
|
1621 | 1612 | } |
|
1622 | 1613 | |
|
1623 | 1614 | .td-todo-gravatar { |
@@ -1641,10 +1632,13 b' table.integrations {' | |||
|
1641 | 1632 | text-overflow: ellipsis; |
|
1642 | 1633 | } |
|
1643 | 1634 | |
|
1635 | table.group_members { | |
|
1636 | width: 100% | |
|
1637 | } | |
|
1638 | ||
|
1644 | 1639 | .group_members { |
|
1645 | 1640 | margin-top: 0; |
|
1646 | 1641 | padding: 0; |
|
1647 | list-style: outside none none; | |
|
1648 | 1642 | |
|
1649 | 1643 | img { |
|
1650 | 1644 | height: @gravatar-size; |
@@ -246,6 +246,8 b' function registerRCRoutes() {' | |||
|
246 | 246 | pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']); |
|
247 | 247 | pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']); |
|
248 | 248 | pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']); |
|
249 | pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']); | |
|
250 | pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']); | |
|
249 | 251 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
250 | 252 | pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); |
|
251 | 253 | pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']); |
@@ -28,9 +28,12 b' export class RhodecodeApp extends Polyme' | |||
|
28 | 28 | super.connectedCallback(); |
|
29 | 29 | ccLog.debug('rhodeCodeApp created'); |
|
30 | 30 | $.Topic('/notifications').subscribe(this.handleNotifications.bind(this)); |
|
31 | $.Topic('/comment').subscribe(this.handleComment.bind(this)); | |
|
31 | 32 | $.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this)); |
|
32 | 33 | $.Topic('/connection_controller/subscribe').subscribe( |
|
33 |
this.subscribeToChannelTopic.bind(this) |
|
|
34 | this.subscribeToChannelTopic.bind(this) | |
|
35 | ); | |
|
36 | ||
|
34 | 37 | // this event can be used to coordinate plugins to do their |
|
35 | 38 | // initialization before channelstream is kicked off |
|
36 | 39 | $.Topic('/__MAIN_APP__').publish({}); |
@@ -71,6 +74,14 b' export class RhodecodeApp extends Polyme' | |||
|
71 | 74 | |
|
72 | 75 | } |
|
73 | 76 | |
|
77 | handleComment(data) { | |
|
78 | if (data.message.comment_id) { | |
|
79 | if (window.refreshAllComments !== undefined) { | |
|
80 | refreshAllComments() | |
|
81 | } | |
|
82 | } | |
|
83 | } | |
|
84 | ||
|
74 | 85 | faviconUpdate(data) { |
|
75 | 86 | this.shadowRoot.querySelector('rhodecode-favicon').counter = data.count; |
|
76 | 87 | } |
@@ -95,6 +106,7 b' export class RhodecodeApp extends Polyme' | |||
|
95 | 106 | } |
|
96 | 107 | // append any additional channels registered in other plugins |
|
97 | 108 | $.Topic('/connection_controller/subscribe').processPrepared(); |
|
109 | ||
|
98 | 110 | channelstreamConnection.connect(); |
|
99 | 111 | } |
|
100 | 112 | } |
@@ -157,8 +169,7 b' export class RhodecodeApp extends Polyme' | |||
|
157 | 169 | |
|
158 | 170 | handleConnected(event) { |
|
159 | 171 | var channelstreamConnection = this.getChannelStreamConnection(); |
|
160 | channelstreamConnection.set('channelsState', | |
|
161 | event.detail.channels_info); | |
|
172 | channelstreamConnection.set('channelsState', event.detail.channels_info); | |
|
162 | 173 | channelstreamConnection.set('userState', event.detail.state); |
|
163 | 174 | channelstreamConnection.set('channels', event.detail.channels); |
|
164 | 175 | this.propagageChannelsState(); |
@@ -677,7 +677,9 b' var feedLifetimeOptions = function(query' | |||
|
677 | 677 | query.callback(data); |
|
678 | 678 | }; |
|
679 | 679 | |
|
680 | ||
|
680 | /* | |
|
681 | * Retrievew via templateContext.session_attrs.key | |
|
682 | * */ | |
|
681 | 683 | var storeUserSessionAttr = function (key, val) { |
|
682 | 684 | |
|
683 | 685 | var postData = { |
@@ -558,7 +558,7 b' var CommentsController = function() {' | |||
|
558 | 558 | return false; |
|
559 | 559 | }; |
|
560 | 560 | |
|
561 |
|
|
|
561 | this.showVersion = function (comment_id, comment_history_id) { | |
|
562 | 562 | |
|
563 | 563 | var historyViewUrl = pyroutes.url( |
|
564 | 564 | 'repo_commit_comment_history_view', |
@@ -585,7 +585,7 b' var CommentsController = function() {' | |||
|
585 | 585 | successRenderCommit, |
|
586 | 586 | failRenderCommit |
|
587 | 587 | ); |
|
588 |
|
|
|
588 | }; | |
|
589 | 589 | |
|
590 | 590 | this.getLineNumber = function(node) { |
|
591 | 591 | var $node = $(node); |
@@ -670,8 +670,20 b' var CommentsController = function() {' | |||
|
670 | 670 | |
|
671 | 671 | var success = function(response) { |
|
672 | 672 | $comment.remove(); |
|
673 | ||
|
674 | if (window.updateSticky !== undefined) { | |
|
675 | // potentially our comments change the active window size, so we | |
|
676 | // notify sticky elements | |
|
677 | updateSticky() | |
|
678 | } | |
|
679 | ||
|
680 | if (window.refreshAllComments !== undefined) { | |
|
681 | // if we have this handler, run it, and refresh all comments boxes | |
|
682 | refreshAllComments() | |
|
683 | } | |
|
673 | 684 | return false; |
|
674 | 685 | }; |
|
686 | ||
|
675 | 687 | var failure = function(jqXHR, textStatus, errorThrown) { |
|
676 | 688 | var prefix = "Error while deleting this comment.\n" |
|
677 | 689 | var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix); |
@@ -682,6 +694,9 b' var CommentsController = function() {' | |||
|
682 | 694 | return false; |
|
683 | 695 | }; |
|
684 | 696 | ajaxPOST(url, postData, success, failure); |
|
697 | ||
|
698 | ||
|
699 | ||
|
685 | 700 | } |
|
686 | 701 | |
|
687 | 702 | this.deleteComment = function(node) { |
@@ -727,6 +742,15 b' var CommentsController = function() {' | |||
|
727 | 742 | $filediff.find('.hide-line-comments').removeClass('hide-line-comments'); |
|
728 | 743 | $filediff.toggleClass('hide-comments'); |
|
729 | 744 | } |
|
745 | ||
|
746 | // since we change the height of the diff container that has anchor points for upper | |
|
747 | // sticky header, we need to tell it to re-calculate those | |
|
748 | if (window.updateSticky !== undefined) { | |
|
749 | // potentially our comments change the active window size, so we | |
|
750 | // notify sticky elements | |
|
751 | updateSticky() | |
|
752 | } | |
|
753 | ||
|
730 | 754 | return false; |
|
731 | 755 | }; |
|
732 | 756 | |
@@ -747,7 +771,7 b' var CommentsController = function() {' | |||
|
747 | 771 | var cm = commentForm.getCmInstance(); |
|
748 | 772 | |
|
749 | 773 | if (resolvesCommentId){ |
|
750 |
|
|
|
774 | placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId); | |
|
751 | 775 | } |
|
752 | 776 | |
|
753 | 777 | setTimeout(function() { |
@@ -1077,9 +1101,15 b' var CommentsController = function() {' | |||
|
1077 | 1101 | updateSticky() |
|
1078 | 1102 | } |
|
1079 | 1103 | |
|
1104 | if (window.refreshAllComments !== undefined) { | |
|
1105 | // if we have this handler, run it, and refresh all comments boxes | |
|
1106 | refreshAllComments() | |
|
1107 | } | |
|
1108 | ||
|
1080 | 1109 | commentForm.setActionButtonsDisabled(false); |
|
1081 | 1110 | |
|
1082 | 1111 | }; |
|
1112 | ||
|
1083 | 1113 | var submitFailCallback = function(jqXHR, textStatus, errorThrown) { |
|
1084 | 1114 | var prefix = "Error while editing comment.\n" |
|
1085 | 1115 | var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix); |
@@ -1209,6 +1239,11 b' var CommentsController = function() {' | |||
|
1209 | 1239 | updateSticky() |
|
1210 | 1240 | } |
|
1211 | 1241 | |
|
1242 | if (window.refreshAllComments !== undefined) { | |
|
1243 | // if we have this handler, run it, and refresh all comments boxes | |
|
1244 | refreshAllComments() | |
|
1245 | } | |
|
1246 | ||
|
1212 | 1247 | commentForm.setActionButtonsDisabled(false); |
|
1213 | 1248 | |
|
1214 | 1249 | }; |
@@ -98,10 +98,13 b' ReviewersController = function () {' | |||
|
98 | 98 | var self = this; |
|
99 | 99 | this.$reviewRulesContainer = $('#review_rules'); |
|
100 | 100 | this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules'); |
|
101 | this.$userRule = $('.pr-user-rule-container'); | |
|
101 | 102 | this.forbidReviewUsers = undefined; |
|
102 | 103 | this.$reviewMembers = $('#review_members'); |
|
103 | 104 | this.currentRequest = null; |
|
104 | 105 | this.diffData = null; |
|
106 | this.enabledRules = []; | |
|
107 | ||
|
105 | 108 | //dummy handler, we might register our own later |
|
106 | 109 | this.diffDataHandler = function(data){}; |
|
107 | 110 | |
@@ -116,14 +119,17 b' ReviewersController = function () {' | |||
|
116 | 119 | |
|
117 | 120 | this.hideReviewRules = function () { |
|
118 | 121 | self.$reviewRulesContainer.hide(); |
|
122 | $(self.$userRule.selector).hide(); | |
|
119 | 123 | }; |
|
120 | 124 | |
|
121 | 125 | this.showReviewRules = function () { |
|
122 | 126 | self.$reviewRulesContainer.show(); |
|
127 | $(self.$userRule.selector).show(); | |
|
123 | 128 | }; |
|
124 | 129 | |
|
125 | 130 | this.addRule = function (ruleText) { |
|
126 | 131 | self.showReviewRules(); |
|
132 | self.enabledRules.push(ruleText); | |
|
127 | 133 | return '<div>- {0}</div>'.format(ruleText) |
|
128 | 134 | }; |
|
129 | 135 | |
@@ -179,6 +185,7 b' ReviewersController = function () {' | |||
|
179 | 185 | _gettext('Reviewers picked from source code changes.')) |
|
180 | 186 | ) |
|
181 | 187 | } |
|
188 | ||
|
182 | 189 | if (data.rules.forbid_adding_reviewers) { |
|
183 | 190 | $('#add_reviewer_input').remove(); |
|
184 | 191 | self.$rulesList.append( |
@@ -186,6 +193,7 b' ReviewersController = function () {' | |||
|
186 | 193 | _gettext('Adding new reviewers is forbidden.')) |
|
187 | 194 | ) |
|
188 | 195 | } |
|
196 | ||
|
189 | 197 | if (data.rules.forbid_author_to_review) { |
|
190 | 198 | self.forbidReviewUsers.push(data.rules_data.pr_author); |
|
191 | 199 | self.$rulesList.append( |
@@ -193,6 +201,7 b' ReviewersController = function () {' | |||
|
193 | 201 | _gettext('Author is not allowed to be a reviewer.')) |
|
194 | 202 | ) |
|
195 | 203 | } |
|
204 | ||
|
196 | 205 | if (data.rules.forbid_commit_author_to_review) { |
|
197 | 206 | |
|
198 | 207 | if (data.rules_data.forbidden_users) { |
@@ -208,6 +217,12 b' ReviewersController = function () {' | |||
|
208 | 217 | ) |
|
209 | 218 | } |
|
210 | 219 | |
|
220 | // we don't have any rules set, so we inform users about it | |
|
221 | if (self.enabledRules.length === 0) { | |
|
222 | self.addRule( | |
|
223 | _gettext('No review rules set.')) | |
|
224 | } | |
|
225 | ||
|
211 | 226 | return self.forbidReviewUsers |
|
212 | 227 | }; |
|
213 | 228 | |
@@ -347,11 +362,12 b' ReviewersController = function () {' | |||
|
347 | 362 | members.innerHTML += renderTemplate('reviewMemberEntry', { |
|
348 | 363 | 'member': reviewer_obj, |
|
349 | 364 | 'mandatory': mandatory, |
|
365 | 'reasons': reasons, | |
|
350 | 366 | 'allowed_to_update': true, |
|
351 | 367 | 'review_status': 'not_reviewed', |
|
352 | 368 | 'review_status_label': _gettext('Not Reviewed'), |
|
353 |
' |
|
|
354 | 'create': true | |
|
369 | 'user_group': reviewer_obj.user_group, | |
|
370 | 'create': true, | |
|
355 | 371 | }); |
|
356 | 372 | tooltipActivate(); |
|
357 | 373 | } |
@@ -600,7 +616,7 b' VersionController = function () {' | |||
|
600 | 616 | var $elem = $(elem); |
|
601 | 617 | var $target = $(target); |
|
602 | 618 | |
|
603 | if ($target.is(':visible')) { | |
|
619 | if ($target.is(':visible') || $target.length === 0) { | |
|
604 | 620 | $target.hide(); |
|
605 | 621 | $elem.html($elem.data('toggleOn')) |
|
606 | 622 | } else { |
@@ -10,12 +10,14 b'' | |||
|
10 | 10 | |
|
11 | 11 | <%namespace name="base" file="/base/base.mako"/> |
|
12 | 12 | <%def name="comment_block(comment, inline=False, active_pattern_entries=None)"> |
|
13 | <% pr_index_ver = comment.get_index_version(getattr(c, 'versions', [])) %> | |
|
13 | ||
|
14 | <% comment_ver = comment.get_index_version(getattr(c, 'versions', [])) %> | |
|
14 | 15 | <% latest_ver = len(getattr(c, 'versions', [])) %> |
|
16 | ||
|
15 | 17 | % if inline: |
|
16 |
<% outdated_at_ver = comment.outdated_at_version( |
|
|
18 | <% outdated_at_ver = comment.outdated_at_version(c.at_version_num) %> | |
|
17 | 19 | % else: |
|
18 |
<% outdated_at_ver = comment.older_than_version( |
|
|
20 | <% outdated_at_ver = comment.older_than_version(c.at_version_num) %> | |
|
19 | 21 | % endif |
|
20 | 22 | |
|
21 | 23 | <div class="comment |
@@ -153,38 +155,38 b'' | |||
|
153 | 155 | </div> |
|
154 | 156 | %endif |
|
155 | 157 | |
|
156 |
<a class="permalink" href="#comment-${comment.comment_id}"> |
|
|
158 | <a class="permalink" href="#comment-${comment.comment_id}">¶ #${comment.comment_id}</a> | |
|
157 | 159 | |
|
158 | 160 | <div class="comment-links-block"> |
|
159 | 161 | |
|
160 | 162 | % if inline: |
|
161 | 163 | <a class="pr-version-inline" href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}"> |
|
162 | 164 | % if outdated_at_ver: |
|
163 |
<code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format( |
|
|
164 |
outdated ${'v{}'.format( |
|
|
165 | <code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}"> | |
|
166 | outdated ${'v{}'.format(comment_ver)} | | |
|
165 | 167 | </code> |
|
166 |
% elif |
|
|
167 |
<code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format( |
|
|
168 |
${'v{}'.format( |
|
|
168 | % elif comment_ver: | |
|
169 | <code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}"> | |
|
170 | ${'v{}'.format(comment_ver)} | | |
|
169 | 171 | </code> |
|
170 | 172 | % endif |
|
171 | 173 | </a> |
|
172 | 174 | % else: |
|
173 |
% if |
|
|
175 | % if comment_ver: | |
|
174 | 176 | |
|
175 | 177 | % if comment.outdated: |
|
176 | 178 | <a class="pr-version" |
|
177 | 179 | href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}" |
|
178 | 180 | > |
|
179 |
${_('Outdated comment from pull request version v{0}, latest v{1}').format( |
|
|
181 | ${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)} | |
|
180 | 182 | </a> | |
|
181 | 183 | % else: |
|
182 | 184 | <a class="tooltip pr-version" |
|
183 |
title="${_('Comment from pull request version v{0}, latest v{1}').format( |
|
|
185 | title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}" | |
|
184 | 186 | href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id, version=comment.pull_request_version_id)}" |
|
185 | 187 | > |
|
186 | 188 | <code class="pr-version-num"> |
|
187 |
${'v{}'.format( |
|
|
189 | ${'v{}'.format(comment_ver)} | |
|
188 | 190 | </code> |
|
189 | 191 | </a> | |
|
190 | 192 | % endif |
@@ -21,8 +21,9 b'' | |||
|
21 | 21 | ## to speed up lookups cache some functions before the loop |
|
22 | 22 | <% |
|
23 | 23 | active_patterns = h.get_active_pattern_entries(c.repo_name) |
|
24 | urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns) | |
|
24 | urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns, issues_container=getattr(c, 'referenced_commit_issues', None)) | |
|
25 | 25 | %> |
|
26 | ||
|
26 | 27 | %for commit in c.commit_ranges: |
|
27 | 28 | <tr id="row-${commit.raw_id}" |
|
28 | 29 | commit_id="${commit.raw_id}" |
@@ -1,6 +1,10 b'' | |||
|
1 | 1 | <%text> |
|
2 | 2 | <div style="display: none"> |
|
3 | 3 | |
|
4 | <script> | |
|
5 | var CG = new ColorGenerator(); | |
|
6 | </script> | |
|
7 | ||
|
4 | 8 | <script id="ejs_gravatarWithUser" type="text/template" class="ejsTemplate"> |
|
5 | 9 | |
|
6 | 10 | <% |
@@ -34,10 +38,6 b" var data_hovercard_url = pyroutes.url('h" | |||
|
34 | 38 | |
|
35 | 39 | </script> |
|
36 | 40 | |
|
37 | <script> | |
|
38 | var CG = new ColorGenerator(); | |
|
39 | </script> | |
|
40 | ||
|
41 | 41 | <script id="ejs_reviewMemberEntry" type="text/template" class="ejsTemplate"> |
|
42 | 42 | <% |
|
43 | 43 | if (create) { |
@@ -47,26 +47,24 b' var CG = new ColorGenerator();' | |||
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | if (member.user_group && member.user_group.vote_rule) { |
|
50 | var groupStyle = 'border-right: 2px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule)); | |
|
50 | var reviewGroup = '<i class="icon-user-group"></i>'; | |
|
51 | var reviewGroupColor = CG.asRGB(CG.getColor(member.user_group.vote_rule)); | |
|
51 | 52 | } else { |
|
52 | var groupStyle = 'border-right: 2px solid transparent'; | |
|
53 | var reviewGroup = null; | |
|
54 | var reviewGroupColor = 'transparent'; | |
|
53 | 55 | } |
|
54 | 56 | %> |
|
55 | 57 | |
|
56 |
< |
|
|
58 | <tr id="reviewer_<%= member.user_id %>" class="reviewer_entry" tooltip="Review Group" data-reviewer-user-id="<%= member.user_id %>"> | |
|
57 | 59 | |
|
58 | <div class="reviewers_member"> | |
|
60 | <td style="width: 20px"> | |
|
59 | 61 | <div class="reviewer_status tooltip" title="<%= review_status_label %>"> |
|
60 | 62 | <i class="icon-circle review-status-<%= review_status %>"></i> |
|
63 | </div> | |
|
64 | </td> | |
|
61 | 65 | |
|
62 |
|
|
|
66 | <td> | |
|
63 | 67 |
|
|
64 | <% if (mandatory) { %> | |
|
65 | <div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer"> | |
|
66 | <i class="icon-lock"></i> | |
|
67 | </div> | |
|
68 | <% } %> | |
|
69 | ||
|
70 | 68 | <%- |
|
71 | 69 | renderTemplate('gravatarWithUser', { |
|
72 | 70 | 'size': 16, |
@@ -78,12 +76,44 b' var CG = new ColorGenerator();' | |||
|
78 | 76 | 'gravatar_url': member.gravatar_link |
|
79 | 77 | }) |
|
80 | 78 | %> |
|
79 | <span class="tooltip presence-state" style="display: none" title="This users is currently at this page"> | |
|
80 | <i class="icon-eye" style="color: #0ac878"></i> | |
|
81 | </span> | |
|
81 | 82 | </div> |
|
83 | </td> | |
|
82 | 84 | |
|
85 | <td style="width: 10px"> | |
|
86 | <% if (reviewGroup !== null) { %> | |
|
87 | <span class="tooltip" title="Member of review group from rule: `<%= member.user_group.name %>`" style="color: <%= reviewGroupColor %>"> | |
|
88 | <%- reviewGroup %> | |
|
89 | </span> | |
|
90 | <% } %> | |
|
91 | </td> | |
|
92 | ||
|
93 | <% if (mandatory) { %> | |
|
94 | <td style="text-align: right;width: 10px;"> | |
|
95 | <div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer"> | |
|
96 | <i class="icon-lock"></i> | |
|
97 | </div> | |
|
98 | </td> | |
|
99 | ||
|
100 | <% } else { %> | |
|
101 | <td> | |
|
102 | <% if (allowed_to_update) { %> | |
|
103 | <div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;"> | |
|
104 | <i class="icon-remove"></i> | |
|
105 | </div> | |
|
106 | <% } %> | |
|
107 | </td> | |
|
108 | <% } %> | |
|
109 | ||
|
110 | </tr> | |
|
111 | ||
|
112 | <tr> | |
|
113 | <td colspan="4" style="display: none" class="pr-user-rule-container"> | |
|
83 | 114 | <input type="hidden" name="__start__" value="reviewer:mapping"> |
|
84 | 115 | |
|
85 | ||
|
86 | <%if (member.user_group && member.user_group.vote_rule) {%> | |
|
116 | <%if (member.user_group && member.user_group.vote_rule) { %> | |
|
87 | 117 | <div class="reviewer_reason"> |
|
88 | 118 | |
|
89 | 119 | <%if (member.user_group.vote_rule == -1) {%> |
@@ -92,7 +122,7 b' var CG = new ColorGenerator();' | |||
|
92 | 122 | - group votes required: <%= member.user_group.vote_rule %> |
|
93 | 123 | <%}%> |
|
94 | 124 | </div> |
|
95 | <%}%> | |
|
125 | <%} %> | |
|
96 | 126 | |
|
97 | 127 | <input type="hidden" name="__start__" value="reasons:sequence"> |
|
98 | 128 | <% for (var i = 0; i < reasons.length; i++) { %> |
@@ -100,37 +130,24 b' var CG = new ColorGenerator();' | |||
|
100 | 130 | <div class="reviewer_reason">- <%= reason %></div> |
|
101 | 131 | <input type="hidden" name="reason" value="<%= reason %>"> |
|
102 | 132 | <% } %> |
|
103 | <input type="hidden" name="__end__" value="reasons:sequence"> | |
|
133 | <input type="hidden" name="__end__" value="reasons:sequence"> | |
|
104 | 134 | |
|
105 | <input type="hidden" name="__start__" value="rules:sequence"> | |
|
135 | <input type="hidden" name="__start__" value="rules:sequence"> | |
|
106 | 136 | <% for (var i = 0; i < member.rules.length; i++) { %> |
|
107 | 137 | <% var rule = member.rules[i] %> |
|
108 | 138 | <input type="hidden" name="rule_id" value="<%= rule %>"> |
|
109 | 139 | <% } %> |
|
110 | <input type="hidden" name="__end__" value="rules:sequence"> | |
|
140 | <input type="hidden" name="__end__" value="rules:sequence"> | |
|
111 | 141 | |
|
112 | <input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" /> | |
|
113 | <input type="hidden" name="mandatory" value="<%= mandatory %>"/> | |
|
142 | <input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" /> | |
|
143 | <input type="hidden" name="mandatory" value="<%= mandatory %>"/> | |
|
114 | 144 | |
|
115 | 145 | <input type="hidden" name="__end__" value="reviewer:mapping"> |
|
116 | ||
|
117 | <% if (mandatory) { %> | |
|
118 | <div class="reviewer_member_mandatory_remove" style="visibility: <%= edit_visibility %>;"> | |
|
119 | <i class="icon-remove"></i> | |
|
120 | </div> | |
|
121 | <% } else { %> | |
|
122 | <% if (allowed_to_update) { %> | |
|
123 | <div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;"> | |
|
124 | <i class="icon-remove" ></i> | |
|
125 | </div> | |
|
126 | <% } %> | |
|
127 | <% } %> | |
|
128 | </div> | |
|
129 | </li> | |
|
146 | </td> | |
|
147 | </tr> | |
|
130 | 148 | |
|
131 | 149 | </script> |
|
132 | 150 | |
|
133 | ||
|
134 | 151 | <script id="ejs_commentVersion" type="text/template" class="ejsTemplate"> |
|
135 | 152 | |
|
136 | 153 | <% |
@@ -158,7 +175,6 b' if (show_disabled) {' | |||
|
158 | 175 | |
|
159 | 176 | </script> |
|
160 | 177 | |
|
161 | ||
|
162 | 178 | </div> |
|
163 | 179 | |
|
164 | 180 | <script> |
@@ -360,13 +360,13 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
360 | 360 | |
|
361 | 361 | div.markdown-block ul.checkbox li, div.markdown-block ol.checkbox li { |
|
362 | 362 | list-style: none !important; |
|
363 |
margin: |
|
|
363 | margin: 0px !important; | |
|
364 | 364 | padding: 0 !important |
|
365 | 365 | } |
|
366 | 366 | |
|
367 | 367 | div.markdown-block ul li, div.markdown-block ol li { |
|
368 | 368 | list-style: disc !important; |
|
369 |
margin: |
|
|
369 | margin: 0px !important; | |
|
370 | 370 | padding: 0 !important |
|
371 | 371 | } |
|
372 | 372 |
This diff has been collapsed as it changes many lines, (1173 lines changed) Show them Hide them | |||
@@ -21,7 +21,120 b'' | |||
|
21 | 21 | ${self.repo_menu(active='showpullrequest')} |
|
22 | 22 | </%def> |
|
23 | 23 | |
|
24 | <%def name="comments_table(comments, counter_num, todo_comments=False)"> | |
|
25 | <% | |
|
26 | old_comments = False | |
|
27 | if todo_comments: | |
|
28 | cls_ = 'todos-content-table' | |
|
29 | def sorter(entry): | |
|
30 | user_id = entry.author.user_id | |
|
31 | resolved = '1' if entry.resolved else '0' | |
|
32 | if user_id == c.rhodecode_user.user_id: | |
|
33 | # own comments first | |
|
34 | user_id = 0 | |
|
35 | return '{}'.format(str(entry.comment_id).zfill(10000)) | |
|
36 | else: | |
|
37 | cls_ = 'comments-content-table' | |
|
38 | def sorter(entry): | |
|
39 | user_id = entry.author.user_id | |
|
40 | return '{}'.format(str(entry.comment_id).zfill(10000)) | |
|
41 | ||
|
42 | ||
|
43 | ||
|
44 | %> | |
|
45 | <table class="todo-table ${cls_}" data-total-count="${len(comments)}" data-counter="${counter_num}"> | |
|
46 | ||
|
47 | % for loop_obj, comment_obj in h.looper(reversed(sorted(comments, key=sorter))): | |
|
48 | <% | |
|
49 | display = '' | |
|
50 | _cls = '' | |
|
51 | %> | |
|
52 | <% comment_ver_index = comment_obj.get_index_version(getattr(c, 'versions', [])) %> | |
|
53 | <% | |
|
54 | prev_comment_ver_index = 0 | |
|
55 | if loop_obj.previous: | |
|
56 | prev_comment_ver_index = loop_obj.previous.get_index_version(getattr(c, 'versions', [])) | |
|
57 | %> | |
|
58 | <% hidden_at_ver = comment_obj.outdated_at_version_js(c.at_version_num) %> | |
|
59 | <% is_from_old_ver = comment_obj.older_than_version_js(c.at_version_num) %> | |
|
60 | <% | |
|
61 | if (prev_comment_ver_index > comment_ver_index) and old_comments is False: | |
|
62 | old_comments = True | |
|
63 | %> | |
|
64 | % if todo_comments: | |
|
65 | % if comment_obj.resolved: | |
|
66 | <% _cls = 'resolved-todo' %> | |
|
67 | <% display = 'none' %> | |
|
68 | % endif | |
|
69 | % else: | |
|
70 | ## SKIP TODOs we display them in other area | |
|
71 | % if comment_obj.is_todo: | |
|
72 | <% display = 'none' %> | |
|
73 | % endif | |
|
74 | ## Skip outdated comments | |
|
75 | % if comment_obj.outdated: | |
|
76 | <% display = 'none' %> | |
|
77 | <% _cls = 'hidden-comment' %> | |
|
78 | % endif | |
|
79 | % endif | |
|
80 | ||
|
81 | % if not todo_comments and old_comments: | |
|
82 | <tr class="old-comments-marker"> | |
|
83 | <td colspan="3"> <code>comments from older versions</code> </td> | |
|
84 | </tr> | |
|
85 | ## reset markers so we only show this marker once | |
|
86 | <% old_comments = None %> | |
|
87 | % endif | |
|
88 | ||
|
89 | <tr class="${_cls}" style="display: ${display};"> | |
|
90 | <td class="td-todo-number"> | |
|
91 | ||
|
92 | <a class="${('todo-resolved' if comment_obj.resolved else '')} permalink" | |
|
93 | href="#comment-${comment_obj.comment_id}" | |
|
94 | onclick="return Rhodecode.comments.scrollToComment($('#comment-${comment_obj.comment_id}'), 0, ${hidden_at_ver})"> | |
|
95 | ||
|
96 | % if todo_comments: | |
|
97 | % if comment_obj.is_inline: | |
|
98 | <i class="tooltip icon-code" title="Inline TODO comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i> | |
|
99 | % else: | |
|
100 | <i class="tooltip icon-comment" title="General TODO comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i> | |
|
101 | % endif | |
|
102 | % else: | |
|
103 | % if comment_obj.outdated: | |
|
104 | <i class="tooltip icon-comment-toggle" title="Inline Outdated made in v${comment_ver_index}."></i> | |
|
105 | % elif comment_obj.is_inline: | |
|
106 | <i class="tooltip icon-code" title="Inline comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i> | |
|
107 | % else: | |
|
108 | <i class="tooltip icon-comment" title="General comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i> | |
|
109 | % endif | |
|
110 | % endif | |
|
111 | ||
|
112 | #${comment_obj.comment_id} | |
|
113 | </a> | |
|
114 | </td> | |
|
115 | ||
|
116 | <td class="td-todo-gravatar"> | |
|
117 | ${base.gravatar(comment_obj.author.email, 16, user=comment_obj.author, tooltip=True, extra_class=['no-margin'])} | |
|
118 | </td> | |
|
119 | <td class="todo-comment-text-wrapper"> | |
|
120 | <div class="tooltip todo-comment-text timeago" title="${h.format_date(comment_obj.created_on)}" datetime="${comment_obj.created_on}${h.get_timezone(comment_obj.created_on, time_is_local=True)}"> | |
|
121 | <code>${h.chop_at_smart(comment_obj.text, '\n', suffix_if_chopped='...')}</code> | |
|
122 | </div> | |
|
123 | </td> | |
|
124 | </tr> | |
|
125 | % endfor | |
|
126 | ||
|
127 | </table> | |
|
128 | ||
|
129 | </%def> | |
|
130 | ||
|
131 | ||
|
24 | 132 | <%def name="main()"> |
|
133 | ## Container to gather extracted Tickets | |
|
134 | <% | |
|
135 | c.referenced_commit_issues = [] | |
|
136 | c.referenced_desc_issues = [] | |
|
137 | %> | |
|
25 | 138 | |
|
26 | 139 | <script type="text/javascript"> |
|
27 | 140 | // TODO: marcink switch this to pyroutes |
@@ -79,7 +192,7 b'' | |||
|
79 | 192 | </div> |
|
80 | 193 | |
|
81 | 194 | <div id="pr-desc" class="input" title="${_('Rendered using {} renderer').format(c.renderer)}"> |
|
82 | ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name)} | |
|
195 | ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name, issues_container=c.referenced_desc_issues)} | |
|
83 | 196 | </div> |
|
84 | 197 | |
|
85 | 198 | <div id="pr-desc-edit" class="input textarea" style="display: none;"> |
@@ -89,29 +202,6 b'' | |||
|
89 | 202 | |
|
90 | 203 | <div id="summary" class="fields pr-details-content"> |
|
91 | 204 | |
|
92 | ## review | |
|
93 | <div class="field"> | |
|
94 | <div class="label-pr-detail"> | |
|
95 | <label>${_('Review status')}:</label> | |
|
96 | </div> | |
|
97 | <div class="input"> | |
|
98 | %if c.pull_request_review_status: | |
|
99 | <div class="tag status-tag-${c.pull_request_review_status}"> | |
|
100 | <i class="icon-circle review-status-${c.pull_request_review_status}"></i> | |
|
101 | <span class="changeset-status-lbl"> | |
|
102 | %if c.pull_request.is_closed(): | |
|
103 | ${_('Closed')}, | |
|
104 | %endif | |
|
105 | ||
|
106 | ${h.commit_status_lbl(c.pull_request_review_status)} | |
|
107 | ||
|
108 | </span> | |
|
109 | </div> | |
|
110 | - ${_ungettext('calculated based on {} reviewer vote', 'calculated based on {} reviewers votes', len(c.pull_request_reviewers)).format(len(c.pull_request_reviewers))} | |
|
111 | %endif | |
|
112 | </div> | |
|
113 | </div> | |
|
114 | ||
|
115 | 205 | ## source |
|
116 | 206 | <div class="field"> |
|
117 | 207 | <div class="label-pr-detail"> |
@@ -231,7 +321,7 b'' | |||
|
231 | 321 | </code> |
|
232 | 322 | </td> |
|
233 | 323 | <td> |
|
234 |
<input ${('checked="checked"' if c.from_version_ |
|
|
324 | <input ${('checked="checked"' if c.from_version_index == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/> | |
|
235 | 325 | <input ${('checked="checked"' if c.at_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/> |
|
236 | 326 | </td> |
|
237 | 327 | <td> |
@@ -281,8 +371,6 b'' | |||
|
281 | 371 | </div> |
|
282 | 372 | |
|
283 | 373 | |
|
284 | ||
|
285 | ||
|
286 | 374 | </div> |
|
287 | 375 | |
|
288 | 376 | </div> |
@@ -339,9 +427,9 b'' | |||
|
339 | 427 | <div class="compare_view_commits_title"> |
|
340 | 428 | % if not c.compare_mode: |
|
341 | 429 | |
|
342 |
% if c.at_version_ |
|
|
430 | % if c.at_version_index: | |
|
343 | 431 | <h4> |
|
344 |
${_('Showing changes at v |
|
|
432 | ${_('Showing changes at v{}, commenting is disabled.').format(c.at_version_index)} | |
|
345 | 433 | </h4> |
|
346 | 434 | % endif |
|
347 | 435 | |
@@ -394,10 +482,11 b'' | |||
|
394 | 482 | </div> |
|
395 | 483 | |
|
396 | 484 | % if not c.missing_commits: |
|
485 | ## COMPARE RANGE DIFF MODE | |
|
397 | 486 | % if c.compare_mode: |
|
398 | 487 | % if c.at_version: |
|
399 | 488 | <h4> |
|
400 |
${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_ |
|
|
489 | ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_index, ver_to=c.at_version_index if c.at_version_index else 'latest')}: | |
|
401 | 490 | </h4> |
|
402 | 491 | |
|
403 | 492 | <div class="subtitle-compare"> |
@@ -452,7 +541,7 b'' | |||
|
452 | 541 | </td> |
|
453 | 542 | <td class="mid td-description"> |
|
454 | 543 | <div class="log-container truncate-wrap"> |
|
455 | <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name)}</div> | |
|
544 | <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name, issues_container=c.referenced_commit_issues)}</div> | |
|
456 | 545 | </div> |
|
457 | 546 | </td> |
|
458 | 547 | </tr> |
@@ -463,21 +552,13 b'' | |||
|
463 | 552 | |
|
464 | 553 | % endif |
|
465 | 554 | |
|
555 | ## Regular DIFF | |
|
466 | 556 | % else: |
|
467 | 557 | <%include file="/compare/compare_commits.mako" /> |
|
468 | 558 | % endif |
|
469 | 559 | |
|
470 | 560 | <div class="cs_files"> |
|
471 | 561 | <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/> |
|
472 | % if c.at_version: | |
|
473 | <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %> | |
|
474 | <% c.inline_comments_flat = c.inline_versions[c.at_version_num]['display'] %> | |
|
475 | <% c.comments = c.comment_versions[c.at_version_num]['display'] %> | |
|
476 | % else: | |
|
477 | <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %> | |
|
478 | <% c.inline_comments_flat = c.inline_versions[c.at_version_num]['until'] %> | |
|
479 | <% c.comments = c.comment_versions[c.at_version_num]['until'] %> | |
|
480 | % endif | |
|
481 | 562 | |
|
482 | 563 | <% |
|
483 | 564 | pr_menu_data = { |
@@ -524,7 +605,7 b'' | |||
|
524 | 605 | ## comments heading with count |
|
525 | 606 | <div class="comments-heading"> |
|
526 | 607 | <i class="icon-comment"></i> |
|
527 | ${_('Comments')} ${len(c.comments)} | |
|
608 | ${_('General Comments')} ${len(c.comments)} | |
|
528 | 609 | </div> |
|
529 | 610 | |
|
530 | 611 | ## render general comments |
@@ -561,6 +642,354 b'' | |||
|
561 | 642 | % endif |
|
562 | 643 | </div> |
|
563 | 644 | |
|
645 | ||
|
646 | ### NAVBOG RIGHT | |
|
647 | <style> | |
|
648 | ||
|
649 | .right-sidebar { | |
|
650 | position: fixed; | |
|
651 | top: 0px; | |
|
652 | bottom: 0; | |
|
653 | right: 0; | |
|
654 | ||
|
655 | background: #fafafa; | |
|
656 | z-index: 50; | |
|
657 | } | |
|
658 | ||
|
659 | .right-sidebar { | |
|
660 | border-left: 1px solid #dbdbdb; | |
|
661 | } | |
|
662 | ||
|
663 | .right-sidebar.right-sidebar-expanded { | |
|
664 | width: 320px; | |
|
665 | overflow: scroll; | |
|
666 | } | |
|
667 | ||
|
668 | .right-sidebar.right-sidebar-collapsed { | |
|
669 | width: 50px; | |
|
670 | padding: 0; | |
|
671 | display: block; | |
|
672 | overflow: hidden; | |
|
673 | } | |
|
674 | ||
|
675 | .sidenav { | |
|
676 | float: right; | |
|
677 | will-change: min-height; | |
|
678 | background: #fafafa; | |
|
679 | width: 100%; | |
|
680 | padding-top: 50px; | |
|
681 | } | |
|
682 | ||
|
683 | .sidebar-toggle { | |
|
684 | height: 30px; | |
|
685 | text-align: center; | |
|
686 | margin: 15px 0px 0 0; | |
|
687 | } | |
|
688 | .sidebar-toggle a { | |
|
689 | ||
|
690 | } | |
|
691 | ||
|
692 | .sidebar-content { | |
|
693 | margin-left: 15px; | |
|
694 | margin-right: 15px; | |
|
695 | } | |
|
696 | ||
|
697 | .sidebar-heading { | |
|
698 | font-size: 1.2em; | |
|
699 | font-weight: 700; | |
|
700 | margin-top: 10px; | |
|
701 | } | |
|
702 | ||
|
703 | .sidebar-element { | |
|
704 | margin-top: 20px; | |
|
705 | } | |
|
706 | .right-sidebar-collapsed-state { | |
|
707 | display: flex; | |
|
708 | flex-direction: column; | |
|
709 | justify-content: center; | |
|
710 | align-items: center; | |
|
711 | padding: 0 10px; | |
|
712 | cursor: pointer; | |
|
713 | font-size: 1.3em; | |
|
714 | margin: 0 -15px; | |
|
715 | } | |
|
716 | ||
|
717 | .right-sidebar-collapsed-state:hover { | |
|
718 | background-color: #dbd9da; | |
|
719 | } | |
|
720 | ||
|
721 | .old-comments-marker { | |
|
722 | text-align: center; | |
|
723 | } | |
|
724 | ||
|
725 | .old-comments-marker td { | |
|
726 | padding-top: 15px; | |
|
727 | border-bottom: 1px solid #dbd9da; | |
|
728 | } | |
|
729 | ||
|
730 | #add_reviewer { | |
|
731 | padding-top: 10px; | |
|
732 | } | |
|
733 | ||
|
734 | </style> | |
|
735 | ||
|
736 | <aside class="right-sidebar right-sidebar-expanded" id="pr-nav-sticky" style="display: none"> | |
|
737 | <div class="sidenav navbar__inner" > | |
|
738 | ## TOGGLE | |
|
739 | <div class="sidebar-toggle" onclick="toggleSidebar(); return false"> | |
|
740 | <a href="#toggleSidebar"> | |
|
741 | ||
|
742 | </a> | |
|
743 | </div> | |
|
744 | ||
|
745 | ## CONTENT | |
|
746 | <div class="sidebar-content"> | |
|
747 | ||
|
748 | ## RULES SUMMARY/RULES | |
|
749 | <div class="sidebar-element clear-both"> | |
|
750 | ||
|
751 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Reviewers')}"> | |
|
752 | <i class="icon-circle review-status-${c.pull_request_review_status}"></i> | |
|
753 | ${len(c.allowed_reviewers)} | |
|
754 | </div> | |
|
755 | ||
|
756 | ## REVIEW RULES | |
|
757 | <div id="review_rules" style="display: none" class=""> | |
|
758 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
759 | <span class="sidebar-heading"> | |
|
760 | ${_('Reviewer rules')} | |
|
761 | </span> | |
|
762 | ||
|
763 | </div> | |
|
764 | <div class="pr-reviewer-rules"> | |
|
765 | ## review rules will be appended here, by default reviewers logic | |
|
766 | </div> | |
|
767 | <input id="review_data" type="hidden" name="review_data" value=""> | |
|
768 | </div> | |
|
769 | ||
|
770 | ## REVIEWERS | |
|
771 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
772 | <span class="tooltip sidebar-heading" title="${_ungettext('Review status calculated based on {} reviewer vote', 'Review status calculated based on {} reviewers votes', len(c.allowed_reviewers)).format(len(c.allowed_reviewers))}"> | |
|
773 | <i class="icon-circle review-status-${c.pull_request_review_status}"></i> | |
|
774 | ${_('Reviewers')} | |
|
775 | </span> | |
|
776 | %if c.allowed_to_update: | |
|
777 | <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span> | |
|
778 | <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span> | |
|
779 | %else: | |
|
780 | <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Show rules')}</span> | |
|
781 | <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span> | |
|
782 | %endif | |
|
783 | </div> | |
|
784 | ||
|
785 | <div id="reviewers" class="right-sidebar-expanded-state pr-details-content reviewers"> | |
|
786 | ||
|
787 | ## members redering block | |
|
788 | <input type="hidden" name="__start__" value="review_members:sequence"> | |
|
789 | ||
|
790 | <table id="review_members" class="group_members"> | |
|
791 | ## This content is loaded via JS and ReviewersPanel | |
|
792 | </table> | |
|
793 | ||
|
794 | <input type="hidden" name="__end__" value="review_members:sequence"> | |
|
795 | ## end members redering block | |
|
796 | ||
|
797 | %if not c.pull_request.is_closed(): | |
|
798 | <div id="add_reviewer" class="ac" style="display: none;"> | |
|
799 | %if c.allowed_to_update: | |
|
800 | % if not c.forbid_adding_reviewers: | |
|
801 | <div id="add_reviewer_input" class="reviewer_ac"> | |
|
802 | ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))} | |
|
803 | <div id="reviewers_container"></div> | |
|
804 | </div> | |
|
805 | % endif | |
|
806 | <div class="pull-right"> | |
|
807 | <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button> | |
|
808 | </div> | |
|
809 | %endif | |
|
810 | </div> | |
|
811 | %endif | |
|
812 | </div> | |
|
813 | </div> | |
|
814 | ||
|
815 | ## ## OBSERVERS | |
|
816 | ## <div class="sidebar-element clear-both"> | |
|
817 | ## <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Observers')}"> | |
|
818 | ## <i class="icon-eye"></i> | |
|
819 | ## 0 | |
|
820 | ## </div> | |
|
821 | ## | |
|
822 | ## <div class="right-sidebar-expanded-state pr-details-title"> | |
|
823 | ## <span class="sidebar-heading"> | |
|
824 | ## <i class="icon-eye"></i> | |
|
825 | ## ${_('Observers')} | |
|
826 | ## </span> | |
|
827 | ## </div> | |
|
828 | ## <div class="right-sidebar-expanded-state pr-details-content"> | |
|
829 | ## No observers | |
|
830 | ## </div> | |
|
831 | ## </div> | |
|
832 | ||
|
833 | ## TODOs | |
|
834 | <div class="sidebar-element clear-both"> | |
|
835 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs"> | |
|
836 | <i class="icon-flag-filled"></i> | |
|
837 | <span id="todos-count">${len(c.unresolved_comments)}</span> | |
|
838 | </div> | |
|
839 | ||
|
840 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
841 | ## Only show unresolved, that is only what matters | |
|
842 | <span class="sidebar-heading noselect" onclick="refreshTODOs(); return false"> | |
|
843 | <i class="icon-flag-filled"></i> | |
|
844 | TODOs | |
|
845 | </span> | |
|
846 | ||
|
847 | % if not c.at_version: | |
|
848 | % if c.resolved_comments: | |
|
849 | <span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.resolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span> | |
|
850 | % else: | |
|
851 | <span class="block-right last-item noselect">Show resolved</span> | |
|
852 | % endif | |
|
853 | % endif | |
|
854 | </div> | |
|
855 | ||
|
856 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
857 | ||
|
858 | % if c.at_version: | |
|
859 | <table> | |
|
860 | <tr> | |
|
861 | <td class="unresolved-todo-text">${_('TODOs unavailable when browsing versions')}.</td> | |
|
862 | </tr> | |
|
863 | </table> | |
|
864 | % else: | |
|
865 | % if c.unresolved_comments + c.resolved_comments: | |
|
866 | ${comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)} | |
|
867 | % else: | |
|
868 | <table> | |
|
869 | <tr> | |
|
870 | <td> | |
|
871 | ${_('No TODOs yet')} | |
|
872 | </td> | |
|
873 | </tr> | |
|
874 | </table> | |
|
875 | % endif | |
|
876 | % endif | |
|
877 | </div> | |
|
878 | </div> | |
|
879 | ||
|
880 | ## COMMENTS | |
|
881 | <div class="sidebar-element clear-both"> | |
|
882 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}"> | |
|
883 | <i class="icon-comment" style="color: #949494"></i> | |
|
884 | <span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span> | |
|
885 | </div> | |
|
886 | ||
|
887 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
888 | <span class="sidebar-heading noselect" onclick="refreshComments(); return false"> | |
|
889 | <i class="icon-comment" style="color: #949494"></i> | |
|
890 | ${_('Comments')} | |
|
891 | ||
|
892 | ## % if outdated_comm_count_ver: | |
|
893 | ## <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;"> | |
|
894 | ## (${_("{} Outdated").format(outdated_comm_count_ver)}) | |
|
895 | ## </a> | |
|
896 | ## <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a> | |
|
897 | ## <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a> | |
|
898 | ||
|
899 | ## % else: | |
|
900 | ## (${_("{} Outdated").format(outdated_comm_count_ver)}) | |
|
901 | ## % endif | |
|
902 | ||
|
903 | </span> | |
|
904 | ||
|
905 | % if outdated_comm_count_ver: | |
|
906 | <span class="block-right action_button last-item noselect" onclick="return versionController.toggleElement(this, '.hidden-comment');" data-toggle-on="Show outdated" data-toggle-off="Hide outdated">Show outdated</span> | |
|
907 | % else: | |
|
908 | <span class="block-right last-item noselect">Show hidden</span> | |
|
909 | % endif | |
|
910 | ||
|
911 | </div> | |
|
912 | ||
|
913 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
914 | % if c.inline_comments_flat + c.comments: | |
|
915 | ${comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))} | |
|
916 | % else: | |
|
917 | <table> | |
|
918 | <tr> | |
|
919 | <td> | |
|
920 | ${_('No Comments yet')} | |
|
921 | </td> | |
|
922 | </tr> | |
|
923 | </table> | |
|
924 | % endif | |
|
925 | </div> | |
|
926 | ||
|
927 | </div> | |
|
928 | ||
|
929 | ## Referenced Tickets | |
|
930 | <div class="sidebar-element clear-both"> | |
|
931 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Referenced Tickets')}"> | |
|
932 | <i class="icon-info-circled"></i> | |
|
933 | ${(len(c.referenced_desc_issues) + len(c.referenced_commit_issues))} | |
|
934 | </div> | |
|
935 | ||
|
936 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
937 | <span class="sidebar-heading"> | |
|
938 | <i class="icon-info-circled"></i> | |
|
939 | ${_('Referenced Tickets')} | |
|
940 | </span> | |
|
941 | </div> | |
|
942 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
943 | <table> | |
|
944 | ||
|
945 | <tr><td><code>${_('Pull Request Description')}</code></td></tr> | |
|
946 | % if c.referenced_desc_issues: | |
|
947 | % for ticket_dict in c.referenced_desc_issues: | |
|
948 | <tr> | |
|
949 | <td> | |
|
950 | <a href="${ticket_dict.get('url')}"> | |
|
951 | ${ticket_dict.get('id')} | |
|
952 | </a> | |
|
953 | </td> | |
|
954 | </tr> | |
|
955 | % endfor | |
|
956 | % else: | |
|
957 | <tr> | |
|
958 | <td> | |
|
959 | ${_('No Ticket data found.')} | |
|
960 | </td> | |
|
961 | </tr> | |
|
962 | % endif | |
|
963 | ||
|
964 | <tr><td style="padding-top: 10px"><code>${_('Commit Messages')}</code></td></tr> | |
|
965 | % if c.referenced_commit_issues: | |
|
966 | % for ticket_dict in c.referenced_commit_issues: | |
|
967 | <tr> | |
|
968 | <td> | |
|
969 | <a href="${ticket_dict.get('url')}"> | |
|
970 | ${ticket_dict.get('id')} | |
|
971 | </a> | |
|
972 | </td> | |
|
973 | </tr> | |
|
974 | % endfor | |
|
975 | % else: | |
|
976 | <tr> | |
|
977 | <td> | |
|
978 | ${_('No Ticket data found.')} | |
|
979 | </td> | |
|
980 | </tr> | |
|
981 | % endif | |
|
982 | </table> | |
|
983 | ||
|
984 | </div> | |
|
985 | </div> | |
|
986 | ||
|
987 | </div> | |
|
988 | ||
|
989 | </div> | |
|
990 | </aside> | |
|
991 | ||
|
992 | ## This JS needs to be at the end | |
|
564 | 993 | <script type="text/javascript"> |
|
565 | 994 | |
|
566 | 995 | versionController = new VersionController(); |
@@ -571,6 +1000,61 b'' | |||
|
571 | 1000 | |
|
572 | 1001 | updateController = new UpdatePrController(); |
|
573 | 1002 | |
|
1003 | /** leak object to top level scope **/ | |
|
1004 | window.PullRequestPresenceController; | |
|
1005 | ||
|
1006 | (function () { | |
|
1007 | "use strict"; | |
|
1008 | ||
|
1009 | window.PullRequestPresenceController = function (channel) { | |
|
1010 | var self = this; | |
|
1011 | this.channel = channel; | |
|
1012 | this.users = {}; | |
|
1013 | ||
|
1014 | this.storeUsers = function (users) { | |
|
1015 | self.users = {} | |
|
1016 | $.each(users, function(index, value) { | |
|
1017 | var userId = value.state.id; | |
|
1018 | self.users[userId] = value.state; | |
|
1019 | }) | |
|
1020 | } | |
|
1021 | ||
|
1022 | this.render = function () { | |
|
1023 | $.each($('.reviewer_entry'), function(index, value) { | |
|
1024 | var userData = $(value).data(); | |
|
1025 | if(self.users[userData.reviewerUserId] !== undefined){ | |
|
1026 | $(value).find('.presence-state').show(); | |
|
1027 | } else { | |
|
1028 | $(value).find('.presence-state').hide(); | |
|
1029 | } | |
|
1030 | }) | |
|
1031 | }; | |
|
1032 | ||
|
1033 | this.handlePresence = function (data) { | |
|
1034 | ||
|
1035 | if (data.type == 'presence' && data.channel === self.channel) { | |
|
1036 | this.storeUsers(data.users); | |
|
1037 | this.render() | |
|
1038 | } | |
|
1039 | }; | |
|
1040 | ||
|
1041 | this.handleChannelUpdate = function (data) { | |
|
1042 | ||
|
1043 | if (data.channel === this.channel) { | |
|
1044 | this.storeUsers(data.state.users); | |
|
1045 | this.render() | |
|
1046 | } | |
|
1047 | ||
|
1048 | }; | |
|
1049 | ||
|
1050 | /* subscribe our chat to topics that are interesting to it */ | |
|
1051 | $.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this)); | |
|
1052 | $.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this)); | |
|
1053 | }; | |
|
1054 | ||
|
1055 | })(); | |
|
1056 | ||
|
1057 | ||
|
574 | 1058 | $(function () { |
|
575 | 1059 | |
|
576 | 1060 | // custom code mirror |
@@ -616,6 +1100,8 b'' | |||
|
616 | 1100 | closeButton: $('#close_edit_reviewers'), |
|
617 | 1101 | addButton: $('#add_reviewer'), |
|
618 | 1102 | removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'), |
|
1103 | reviewRules: ${c.pull_request_default_reviewers_data_json | n}, | |
|
1104 | setReviewers: ${c.pull_request_set_reviewers_data_json | n}, | |
|
619 | 1105 | |
|
620 | 1106 | init: function () { |
|
621 | 1107 | var self = this; |
@@ -624,24 +1110,50 b'' | |||
|
624 | 1110 | }); |
|
625 | 1111 | this.closeButton.on('click', function (e) { |
|
626 | 1112 | self.close(); |
|
1113 | self.renderReviewers(); | |
|
627 | 1114 | }); |
|
1115 | ||
|
1116 | self.renderReviewers(); | |
|
1117 | ||
|
1118 | }, | |
|
1119 | ||
|
1120 | renderReviewers: function () { | |
|
1121 | ||
|
1122 | $('#review_members').html('') | |
|
1123 | $.each(this.setReviewers.reviewers, function (key, val) { | |
|
1124 | var member = val; | |
|
1125 | ||
|
1126 | var entry = renderTemplate('reviewMemberEntry', { | |
|
1127 | 'member': member, | |
|
1128 | 'mandatory': member.mandatory, | |
|
1129 | 'reasons': member.reasons, | |
|
1130 | 'allowed_to_update': member.allowed_to_update, | |
|
1131 | 'review_status': member.review_status, | |
|
1132 | 'review_status_label': member.review_status_label, | |
|
1133 | 'user_group': member.user_group, | |
|
1134 | 'create': false | |
|
1135 | }); | |
|
1136 | ||
|
1137 | $('#review_members').append(entry) | |
|
1138 | }); | |
|
1139 | tooltipActivate(); | |
|
1140 | ||
|
628 | 1141 | }, |
|
629 | 1142 | |
|
630 | 1143 | edit: function (event) { |
|
631 | 1144 | this.editButton.hide(); |
|
632 | 1145 | this.closeButton.show(); |
|
633 | 1146 | this.addButton.show(); |
|
634 | this.removeButtons.css('visibility', 'visible'); | |
|
1147 | $(this.removeButtons.selector).css('visibility', 'visible'); | |
|
635 | 1148 | // review rules |
|
636 | reviewersController.loadReviewRules( | |
|
637 | ${c.pull_request.reviewer_data_json | n}); | |
|
1149 | reviewersController.loadReviewRules(this.reviewRules); | |
|
638 | 1150 | }, |
|
639 | 1151 | |
|
640 | 1152 | close: function (event) { |
|
641 | 1153 | this.editButton.show(); |
|
642 | 1154 | this.closeButton.hide(); |
|
643 | 1155 | this.addButton.hide(); |
|
644 | this.removeButtons.css('visibility', 'hidden'); | |
|
1156 | $(this.removeButtons.selector).css('visibility', 'hidden'); | |
|
645 | 1157 | // hide review rules |
|
646 | 1158 | reviewersController.hideReviewRules() |
|
647 | 1159 | } |
@@ -670,14 +1182,83 b'' | |||
|
670 | 1182 | $('.action-buttons-extra').css('opacity', 0.3); |
|
671 | 1183 | |
|
672 | 1184 | $('.pull-request-merge').load( |
|
673 |
|
|
|
674 |
|
|
|
1185 | loadUrl, function () { | |
|
1186 | $('.pull-request-merge').css('opacity', 1); | |
|
675 | 1187 | |
|
676 |
|
|
|
677 |
|
|
|
1188 | $('.action-buttons-extra').css('opacity', 1); | |
|
1189 | } | |
|
678 | 1190 | ); |
|
679 | 1191 | }; |
|
680 | 1192 | |
|
1193 | refreshComments = function () { | |
|
1194 | var params = { | |
|
1195 | 'pull_request_id': templateContext.pull_request_data.pull_request_id, | |
|
1196 | 'repo_name': templateContext.repo_name, | |
|
1197 | 'version': '${request.GET.get('version', '')}', | |
|
1198 | }; | |
|
1199 | var data = {"comments[]": ["1"]}; | |
|
1200 | var loadUrl = pyroutes.url('pullrequest_comments', params); | |
|
1201 | var $targetElem = $('.comments-content-table'); | |
|
1202 | $targetElem.css('opacity', 0.3); | |
|
1203 | $targetElem.load( | |
|
1204 | loadUrl, data, function (responseText, textStatus, jqXHR) { | |
|
1205 | if (jqXHR.status !== 200) { | |
|
1206 | return false; | |
|
1207 | } | |
|
1208 | var $counterElem = $('#comments-count'); | |
|
1209 | var newCount = $(responseText).data('counter'); | |
|
1210 | if (newCount !== undefined) { | |
|
1211 | var callback = function () { | |
|
1212 | $counterElem.animate({'opacity': 1.00}, 200) | |
|
1213 | $counterElem.html(newCount); | |
|
1214 | }; | |
|
1215 | $counterElem.animate({'opacity': 0.15}, 200, callback); | |
|
1216 | } | |
|
1217 | ||
|
1218 | ||
|
1219 | $targetElem.css('opacity', 1); | |
|
1220 | tooltipActivate(); | |
|
1221 | } | |
|
1222 | ); | |
|
1223 | } | |
|
1224 | ||
|
1225 | refreshTODOs = function () { | |
|
1226 | var params = { | |
|
1227 | 'pull_request_id': templateContext.pull_request_data.pull_request_id, | |
|
1228 | 'repo_name': templateContext.repo_name, | |
|
1229 | 'version': '${request.GET.get('version', '')}', | |
|
1230 | }; | |
|
1231 | var data = {"comments[]": ["1"]}; | |
|
1232 | var loadUrl = pyroutes.url('pullrequest_todos', params); | |
|
1233 | var $targetElem = $('.todos-content-table'); | |
|
1234 | $targetElem.css('opacity', 0.3); | |
|
1235 | $targetElem.load( | |
|
1236 | loadUrl, data, function (responseText, textStatus, jqXHR) { | |
|
1237 | if (jqXHR.status !== 200) { | |
|
1238 | return false; | |
|
1239 | } | |
|
1240 | var $counterElem = $('#todos-count') | |
|
1241 | var newCount = $(responseText).data('counter'); | |
|
1242 | if (newCount !== undefined) { | |
|
1243 | var callback = function () { | |
|
1244 | $counterElem.animate({'opacity': 1.00}, 200) | |
|
1245 | $counterElem.html(newCount); | |
|
1246 | }; | |
|
1247 | $counterElem.animate({'opacity': 0.15}, 200, callback); | |
|
1248 | } | |
|
1249 | ||
|
1250 | $targetElem.css('opacity', 1); | |
|
1251 | tooltipActivate(); | |
|
1252 | } | |
|
1253 | ); | |
|
1254 | ||
|
1255 | } | |
|
1256 | ||
|
1257 | refreshAllComments = function() { | |
|
1258 | refreshComments(); | |
|
1259 | refreshTODOs(); | |
|
1260 | } | |
|
1261 | ||
|
681 | 1262 | closePullRequest = function (status) { |
|
682 | 1263 | if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) { |
|
683 | 1264 | return false; |
@@ -771,441 +1352,91 b'' | |||
|
771 | 1352 | |
|
772 | 1353 | }) |
|
773 | 1354 | |
|
774 | </script> | |
|
775 | ||
|
776 | ||
|
777 | ### NAVBOG RIGHT | |
|
778 | <style> | |
|
779 | ||
|
780 | .right-sidebar { | |
|
781 | position: fixed; | |
|
782 | top: 0px; | |
|
783 | bottom: 0; | |
|
784 | right: 0; | |
|
785 | ||
|
786 | background: #fafafa; | |
|
787 | z-index: 200; | |
|
788 | } | |
|
789 | ||
|
790 | .right-sidebar { | |
|
791 | border-left: 1px solid #dbdbdb; | |
|
792 | } | |
|
793 | ||
|
794 | .right-sidebar.right-sidebar-expanded { | |
|
795 | width: 320px; | |
|
796 | overflow: scroll; | |
|
797 | } | |
|
798 | ||
|
799 | .right-sidebar.right-sidebar-collapsed { | |
|
800 | width: 62px; | |
|
801 | padding: 0; | |
|
802 | display: block; | |
|
803 | overflow: hidden; | |
|
804 | } | |
|
805 | ||
|
806 | .sidenav { | |
|
807 | float: right; | |
|
808 | will-change: min-height; | |
|
809 | background: #fafafa; | |
|
810 | width: 100%; | |
|
811 | } | |
|
812 | ||
|
813 | .sidebar-toggle { | |
|
814 | height: 30px; | |
|
815 | text-align: center; | |
|
816 | margin: 15px 0 0 0; | |
|
817 | } | |
|
818 | .sidebar-toggle a { | |
|
819 | ||
|
820 | } | |
|
821 | ||
|
822 | .sidebar-content { | |
|
823 | margin-left: 5px; | |
|
824 | margin-right: 5px; | |
|
825 | } | |
|
826 | ||
|
827 | .sidebar-heading { | |
|
828 | font-size: 1.2em; | |
|
829 | font-weight: 700; | |
|
830 | margin-top: 10px; | |
|
831 | } | |
|
832 | ||
|
833 | .sidebar-element { | |
|
834 | margin-top: 20px; | |
|
835 | } | |
|
836 | .right-sidebar-collapsed-state { | |
|
837 | display: flex; | |
|
838 | flex-direction: column; | |
|
839 | justify-content: center; | |
|
840 | align-items: center; | |
|
841 | padding: 0 10px; | |
|
842 | cursor: pointer; | |
|
843 | font-size: 1.3em; | |
|
844 | margin: 0 -10px; | |
|
845 | } | |
|
846 | ||
|
847 | .right-sidebar-collapsed-state:hover { | |
|
848 | background-color: #dbd9da; | |
|
849 | } | |
|
850 | ||
|
851 | .navbar__inner { | |
|
852 | height: 100%; | |
|
853 | background: #fafafa; | |
|
854 | position: relative; | |
|
855 | } | |
|
856 | ||
|
857 | </style> | |
|
858 | ||
|
859 | ||
|
860 | ||
|
861 | <aside class="right-sidebar right-sidebar-expanded"> | |
|
862 | <div class="sidenav"> | |
|
863 | ## TOGGLE | |
|
864 | <div class="sidebar-toggle" onclick="toggleSidebar(); return false"> | |
|
865 | <a href="#toggleSidebar"> | |
|
866 | ||
|
867 | </a> | |
|
868 | </div> | |
|
869 | ||
|
870 | ## CONTENT | |
|
871 | <div class="sidebar-content"> | |
|
1355 | $(document).ready(function () { | |
|
872 | 1356 | |
|
873 | ## RULES SUMMARY/RULES | |
|
874 | <div class="sidebar-element clear-both"> | |
|
875 | ||
|
876 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Reviewers')}"> | |
|
877 | <i class="icon-circle review-status-${c.pull_request_review_status}"></i> | |
|
878 | <br/>${len(c.pull_request_reviewers)} | |
|
879 | </div> | |
|
880 | ||
|
881 | ## REVIEW RULES | |
|
882 | <div id="review_rules" style="display: none" class=""> | |
|
883 | <div class="pr-details-title"> | |
|
884 | <span class="sidebar-heading"> | |
|
885 | ${_('Reviewer rules')} | |
|
886 | </span> | |
|
887 | ||
|
888 | </div> | |
|
889 | <div class="pr-reviewer-rules"> | |
|
890 | ## review rules will be appended here, by default reviewers logic | |
|
891 | </div> | |
|
892 | <input id="review_data" type="hidden" name="review_data" value=""> | |
|
893 | </div> | |
|
894 | ||
|
895 | ## REVIEWERS | |
|
896 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
897 | <span class="sidebar-heading"> | |
|
898 | <i class="icon-circle review-status-${c.pull_request_review_status}"></i> | |
|
899 | ${_('Reviewers')} - ${len(c.pull_request_reviewers)} | |
|
900 | </span> | |
|
901 | %if c.allowed_to_update: | |
|
902 | <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span> | |
|
903 | <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span> | |
|
904 | %endif | |
|
905 | </div> | |
|
906 | <div id="reviewers" class="right-sidebar-expanded-state pr-details-content reviewers"> | |
|
907 | ||
|
908 | ## members redering block | |
|
909 | <input type="hidden" name="__start__" value="review_members:sequence"> | |
|
910 | <ul id="review_members" class="group_members"> | |
|
911 | ||
|
912 | % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers: | |
|
913 | <script> | |
|
914 | var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n}; | |
|
915 | var status = "${(status[0][1].status if status else 'not_reviewed')}"; | |
|
916 | var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}"; | |
|
917 | var allowed_to_update = ${h.json.dumps(c.allowed_to_update)}; | |
|
918 | ||
|
919 | var entry = renderTemplate('reviewMemberEntry', { | |
|
920 | 'member': member, | |
|
921 | 'mandatory': member.mandatory, | |
|
922 | 'reasons': member.reasons, | |
|
923 | 'allowed_to_update': allowed_to_update, | |
|
924 | 'review_status': status, | |
|
925 | 'review_status_label': status_lbl, | |
|
926 | 'user_group': member.user_group, | |
|
927 | 'create': false | |
|
928 | }); | |
|
929 | $('#review_members').append(entry) | |
|
930 | </script> | |
|
931 | ||
|
932 | % endfor | |
|
933 | ||
|
934 | </ul> | |
|
935 | ||
|
936 | <input type="hidden" name="__end__" value="review_members:sequence"> | |
|
937 | ## end members redering block | |
|
938 | ||
|
939 | %if not c.pull_request.is_closed(): | |
|
940 | <div id="add_reviewer" class="ac" style="display: none;"> | |
|
941 | %if c.allowed_to_update: | |
|
942 | % if not c.forbid_adding_reviewers: | |
|
943 | <div id="add_reviewer_input" class="reviewer_ac"> | |
|
944 | ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))} | |
|
945 | <div id="reviewers_container"></div> | |
|
946 | </div> | |
|
947 | % endif | |
|
948 | <div class="pull-right"> | |
|
949 | <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button> | |
|
950 | </div> | |
|
951 | %endif | |
|
952 | </div> | |
|
953 | %endif | |
|
954 | </div> | |
|
955 | </div> | |
|
956 | ||
|
957 | ## OBSERVERS | |
|
958 | <div class="sidebar-element clear-both"> | |
|
959 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Observers')}"> | |
|
960 | <i class="icon-eye"></i> | |
|
961 | <br/> 0 | |
|
962 | </div> | |
|
963 | ||
|
964 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
965 | <span class="sidebar-heading"> | |
|
966 | <i class="icon-eye"></i> | |
|
967 | ${_('Observers')} | |
|
968 | </span> | |
|
969 | </div> | |
|
970 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
971 | No observers - 0 | |
|
972 | </div> | |
|
973 | </div> | |
|
1357 | var $sideBar = $('.right-sidebar'); | |
|
1358 | var marginExpVal = '320' | |
|
1359 | var marginColVal = '50' | |
|
1360 | var marginExpanded = {'margin': '0 {0}px 0 0'.format(marginExpVal)}; | |
|
1361 | var marginCollapsed = {'margin': '0 {0}px 0 0'.format(marginColVal)}; | |
|
1362 | var marginExpandedHeader = {'margin': '0 -{0}px 0 0'.format(marginExpVal), 'z-index': 10000}; | |
|
1363 | var marginCollapsedHeader = {'margin': '0 -{0}px 0 0'.format(marginColVal), 'z-index': 10000}; | |
|
974 | 1364 | |
|
975 | ## TODOs | |
|
976 | <div class="sidebar-element clear-both"> | |
|
977 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs"> | |
|
978 | <i class="icon-flag-filled"></i> | |
|
979 | <br/> ${len(c.unresolved_comments)} | |
|
980 |
|
|
|
981 | ||
|
982 | ## TODOs will be listed here | |
|
983 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
984 | ## Only show unresolved, that is only what matters | |
|
985 | <span class="sidebar-heading"> | |
|
986 | <i class="icon-flag-filled"></i> | |
|
987 | TODOs - ${len(c.unresolved_comments)} | |
|
988 | ##/ ${(len(c.unresolved_comments) + len(c.resolved_comments))} | |
|
989 | </span> | |
|
990 | ||
|
991 | % if not c.at_version: | |
|
992 | % if c.resolved_comments: | |
|
993 | <span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.unresolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span> | |
|
994 | % else: | |
|
995 | <span class="block-right last-item noselect">Show resolved</span> | |
|
996 | % endif | |
|
997 | % endif | |
|
998 | </div> | |
|
999 | ||
|
1000 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
1001 | ||
|
1002 | <table class="todo-table"> | |
|
1003 | <% | |
|
1004 | def sorter(entry): | |
|
1005 | user_id = entry.author.user_id | |
|
1006 | resolved = '1' if entry.resolved else '0' | |
|
1007 | if user_id == c.rhodecode_user.user_id: | |
|
1008 | # own comments first | |
|
1009 | user_id = 0 | |
|
1010 | return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100)) | |
|
1011 | %> | |
|
1012 | ||
|
1013 | % if c.at_version: | |
|
1014 | <tr> | |
|
1015 | <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td> | |
|
1016 | </tr> | |
|
1017 | % else: | |
|
1018 | % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter): | |
|
1019 | <% resolved = todo_comment.resolved %> | |
|
1020 | % if inline: | |
|
1021 | <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %> | |
|
1022 | % else: | |
|
1023 | <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %> | |
|
1024 | % endif | |
|
1025 | ||
|
1026 | <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}> | |
|
1027 | ||
|
1028 | <td class="td-todo-number"> | |
|
1029 | % if resolved: | |
|
1030 | <a class="permalink todo-resolved tooltip" title="${_('Resolved by comment #{}').format(todo_comment.resolved.comment_id)}" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})"> | |
|
1031 | <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a> | |
|
1032 | % else: | |
|
1033 | <a class="permalink" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})"> | |
|
1034 | <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a> | |
|
1035 | % endif | |
|
1036 | </td> | |
|
1037 | <td class="td-todo-gravatar"> | |
|
1038 | ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])} | |
|
1039 | </td> | |
|
1040 | <td class="todo-comment-text-wrapper"> | |
|
1041 | <div class="todo-comment-text"> | |
|
1042 | <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code> | |
|
1043 | </div> | |
|
1044 | </td> | |
|
1045 | ||
|
1046 | </tr> | |
|
1047 | % endfor | |
|
1048 | ||
|
1049 | % if len(c.unresolved_comments) == 0: | |
|
1050 | <tr> | |
|
1051 | <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td> | |
|
1052 | </tr> | |
|
1053 | % endif | |
|
1054 | ||
|
1055 | % endif | |
|
1056 | ||
|
1057 | </table> | |
|
1058 | ||
|
1059 | </div> | |
|
1060 | </div> | |
|
1061 | ||
|
1062 | ## COMMENTS | |
|
1063 | <div class="sidebar-element clear-both"> | |
|
1064 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}"> | |
|
1065 | <i class="icon-comment" style="color: #949494"></i> | |
|
1066 | <br/> ${len(c.inline_comments_flat+c.comments)} | |
|
1067 | </div> | |
|
1068 | ||
|
1069 | <div class="right-sidebar-expanded-state pr-details-title"> | |
|
1070 | <span class="sidebar-heading"> | |
|
1071 | <i class="icon-comment" style="color: #949494"></i> | |
|
1072 | ${_('Comments')} - ${len(c.inline_comments_flat+c.comments)} | |
|
1073 | ##${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))} / | |
|
1074 | ##${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(len(c.inline_comments_flat))} | |
|
1365 | var updateStickyHeader = function() { | |
|
1366 | if (window.updateSticky !== undefined) { | |
|
1367 | // potentially our comments change the active window size, so we | |
|
1368 | // notify sticky elements | |
|
1369 | updateSticky() | |
|
1370 | } | |
|
1371 | } | |
|
1075 | 1372 |
|
|
1076 | ## TODO check why this ins't working | |
|
1077 | % if pull_request_menu: | |
|
1078 | <% | |
|
1079 | outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver'] | |
|
1080 | %> | |
|
1081 | ||
|
1082 | % if outdated_comm_count_ver: | |
|
1083 | <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;"> | |
|
1084 | (${_("{} Outdated").format(outdated_comm_count_ver)}) | |
|
1085 | </a> | |
|
1086 | <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a> | |
|
1087 | <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a> | |
|
1088 | % else: | |
|
1089 | (${_("{} Outdated").format(outdated_comm_count_ver)}) | |
|
1090 | % endif | |
|
1091 | ||
|
1092 | % endif | |
|
1093 | </span> | |
|
1094 | <span class="block-right action_button last-item noselect" onclick="return versionController.toggleElement(this, '.hidden-comment');" data-toggle-on="Show all" data-toggle-off="Hide all">Show all</span> | |
|
1095 | </div> | |
|
1096 | ||
|
1097 | <div class="right-sidebar-expanded-state pr-details-content"> | |
|
1098 | <table class="todo-table"> | |
|
1099 | <% | |
|
1100 | def sorter(entry): | |
|
1101 | user_id = entry.author.user_id | |
|
1102 | return '{}'.format(str(entry.comment_id).zfill(100)) | |
|
1103 | %> | |
|
1104 | ||
|
1105 | % for comment_obj in reversed(sorted(c.inline_comments_flat + c.comments, key=sorter)): | |
|
1106 | <% | |
|
1107 | display = '' | |
|
1108 | _cls = '' | |
|
1109 | %> | |
|
1110 | ## SKIP TODOs we display them above | |
|
1111 | % if comment_obj.is_todo: | |
|
1112 | <% display = 'none' %> | |
|
1113 | % endif | |
|
1114 | ||
|
1115 | ## Skip outdated comments | |
|
1116 | % if comment_obj.outdated: | |
|
1117 | <% display = 'none' %> | |
|
1118 | <% _cls = 'hidden-comment' %> | |
|
1119 | % endif | |
|
1373 | var expandSidebar = function() { | |
|
1374 | var $sideBar = $('.right-sidebar'); | |
|
1375 | $('.outerwrapper').css(marginExpanded); | |
|
1376 | $('.header').css(marginExpandedHeader); | |
|
1377 | $('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>'); | |
|
1378 | $('.right-sidebar-collapsed-state').hide(); | |
|
1379 | $('.right-sidebar-expanded-state').show(); | |
|
1120 | 1380 | |
|
1121 | <tr class="${_cls}" style="display: ${display}"> | |
|
1122 | <td class="td-todo-number"> | |
|
1123 | <a class="permalink" href="#comment-${comment_obj.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${comment_obj.comment_id}'), 0, ${comment_obj.outdated_js})"> | |
|
1124 | % if comment_obj.outdated: | |
|
1125 | <i class="tooltip icon-comment-toggle" title="Outdated"></i> | |
|
1126 | % elif comment_obj.is_inline: | |
|
1127 | <i class="tooltip icon-code" title="Inline"></i> | |
|
1128 | % else: | |
|
1129 | <i class="tooltip icon-comment" title="General"></i> | |
|
1130 | % endif | |
|
1131 | ${comment_obj.comment_id} | |
|
1132 | </a> | |
|
1133 | </td> | |
|
1134 | <td class="td-todo-gravatar"> | |
|
1135 | ${base.gravatar(comment_obj.author.email, 16, user=comment_obj.author, tooltip=True, extra_class=['no-margin'])} | |
|
1136 | </td> | |
|
1137 | <td class="todo-comment-text-wrapper"> | |
|
1138 | <div class="todo-comment-text"> | |
|
1139 | <code>${h.chop_at_smart(comment_obj.text, '\n', suffix_if_chopped='...')}</code> | |
|
1140 | </div> | |
|
1141 | </td> | |
|
1142 | </tr> | |
|
1143 | % endfor | |
|
1144 | ||
|
1145 | </table> | |
|
1146 | </div> | |
|
1147 | ||
|
1148 | </div> | |
|
1149 | </div> | |
|
1381 | $sideBar.addClass('right-sidebar-expanded') | |
|
1382 | $sideBar.removeClass('right-sidebar-collapsed') | |
|
1383 | } | |
|
1150 | 1384 | |
|
1151 | </div> | |
|
1152 | </aside> | |
|
1153 | ||
|
1154 | ||
|
1155 | <script> | |
|
1156 | var $sideBar = $('.right-sidebar'); | |
|
1157 | var marginExpanded = {'margin': '0 320px 0 0'}; | |
|
1158 | var marginCollapsed = {'margin': '0 50px 0 0'}; | |
|
1159 | ||
|
1160 | if($sideBar.hasClass('right-sidebar-expanded')) { | |
|
1161 | $('.outerwrapper').css(marginExpanded); | |
|
1162 | $('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>'); | |
|
1163 | $('.right-sidebar-collapsed-state').hide(); | |
|
1164 | $('.right-sidebar-expanded-state').show(); | |
|
1165 | updateSticky() | |
|
1166 | ||
|
1167 | } else { | |
|
1168 | $('.outerwrapper').css(marginCollapsed); | |
|
1169 | $('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>'); | |
|
1170 | $('.right-sidebar-collapsed-state').hide(); | |
|
1171 | $('.right-sidebar-expanded-state').show(); | |
|
1172 | updateSticky() | |
|
1173 | } | |
|
1174 | ||
|
1175 | var toggleSidebar = function(){ | |
|
1176 | var $sideBar = $('.right-sidebar'); | |
|
1177 | ||
|
1178 | if($sideBar.hasClass('right-sidebar-expanded')) { | |
|
1179 | // collapse now | |
|
1180 | $sideBar.removeClass('right-sidebar-expanded') | |
|
1181 | $sideBar.addClass('right-sidebar-collapsed') | |
|
1385 | var collapseSidebar = function() { | |
|
1386 | var $sideBar = $('.right-sidebar'); | |
|
1182 | 1387 | $('.outerwrapper').css(marginCollapsed); |
|
1388 | $('.header').css(marginCollapsedHeader); | |
|
1183 | 1389 | $('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>'); |
|
1184 | 1390 | $('.right-sidebar-collapsed-state').show(); |
|
1185 | 1391 | $('.right-sidebar-expanded-state').hide(); |
|
1186 | 1392 | |
|
1187 | } else { | |
|
1188 | // expand now | |
|
1189 | $('.outerwrapper').css(marginExpanded); | |
|
1190 | $sideBar.addClass('right-sidebar-expanded') | |
|
1191 | $sideBar.removeClass('right-sidebar-collapsed') | |
|
1192 | $('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>'); | |
|
1193 | $('.right-sidebar-collapsed-state').hide(); | |
|
1194 |
|
|
|
1393 | $sideBar.removeClass('right-sidebar-expanded') | |
|
1394 | $sideBar.addClass('right-sidebar-collapsed') | |
|
1395 | } | |
|
1396 | ||
|
1397 | toggleSidebar = function () { | |
|
1398 | var $sideBar = $('.right-sidebar'); | |
|
1399 | ||
|
1400 | if ($sideBar.hasClass('right-sidebar-expanded')) { | |
|
1401 | // expanded -> collapsed transition | |
|
1402 | collapseSidebar(); | |
|
1403 | var sidebarState = 'collapsed'; | |
|
1404 | ||
|
1405 | } else { | |
|
1406 | // collapsed -> expanded | |
|
1407 | expandSidebar(); | |
|
1408 | var sidebarState = 'expanded'; | |
|
1409 | } | |
|
1410 | ||
|
1411 | // update our other sticky header in same context | |
|
1412 | updateStickyHeader(); | |
|
1413 | storeUserSessionAttr('rc_user_session_attr.sidebarState', sidebarState); | |
|
1195 | 1414 | } |
|
1196 | 1415 | |
|
1197 | // update our other sticky header in same context | |
|
1198 | updateSticky() | |
|
1199 | } | |
|
1416 | var expanded = $sideBar.hasClass('right-sidebar-expanded'); | |
|
1200 | 1417 | |
|
1201 | var sidebarElement = document.getElementById('pr-nav-sticky'); | |
|
1418 | if (templateContext.session_attrs.sidebarState === 'expanded') { | |
|
1419 | expanded = true | |
|
1420 | } else if (templateContext.session_attrs.sidebarState === 'collapsed') { | |
|
1421 | expanded = false | |
|
1422 | } | |
|
1423 | ||
|
1424 | // show sidebar since it's hidden on load | |
|
1425 | $('.right-sidebar').show(); | |
|
1202 | 1426 | |
|
1203 | ## sidebar = new StickySidebar(sidebarElement, { | |
|
1204 | ## containerSelector: '.main', | |
|
1205 | ## minWidth: 62, | |
|
1206 | ## innerWrapperSelector: '.navbar__inner', | |
|
1207 | ## stickyClass: 'is-sticky', | |
|
1208 | ## }); | |
|
1427 | // init based on set initial class, or if defined user session attrs | |
|
1428 | if (expanded) { | |
|
1429 | expandSidebar(); | |
|
1430 | updateStickyHeader(); | |
|
1209 | 1431 | |
|
1210 | </script> | |
|
1432 | } else { | |
|
1433 | collapseSidebar(); | |
|
1434 | updateStickyHeader(); | |
|
1435 | } | |
|
1436 | var channel = '${c.pr_broadcast_channel}'; | |
|
1437 | new PullRequestPresenceController(channel) | |
|
1438 | ||
|
1439 | }) | |
|
1440 | </script> | |
|
1441 | ||
|
1211 | 1442 | </%def> |
General Comments 0
You need to be logged in to leave comments.
Login now