Show More
@@ -355,6 +355,11 b' def includeme(config):' | |||
|
355 | 355 | pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos', |
|
356 | 356 | repo_route=True) |
|
357 | 357 | |
|
358 | config.add_route( | |
|
359 | name='pullrequest_drafts', | |
|
360 | pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/drafts', | |
|
361 | repo_route=True) | |
|
362 | ||
|
358 | 363 | # Artifacts, (EE feature) |
|
359 | 364 | config.add_route( |
|
360 | 365 | name='repo_artifacts_list', |
@@ -501,6 +501,11 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
501 | 501 | c.resolved_comments = CommentsModel() \ |
|
502 | 502 | .get_pull_request_resolved_todos(pull_request_latest) |
|
503 | 503 | |
|
504 | # Drafts | |
|
505 | c.draft_comments = CommentsModel().get_pull_request_drafts( | |
|
506 | self._rhodecode_db_user.user_id, | |
|
507 | pull_request_latest) | |
|
508 | ||
|
504 | 509 | # if we use version, then do not show later comments |
|
505 | 510 | # than current version |
|
506 | 511 | display_inline_comments = collections.defaultdict( |
@@ -1071,6 +1076,48 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
1071 | 1076 | @NotAnonymous() |
|
1072 | 1077 | @HasRepoPermissionAnyDecorator( |
|
1073 | 1078 | 'repository.read', 'repository.write', 'repository.admin') |
|
1079 | @view_config( | |
|
1080 | route_name='pullrequest_drafts', request_method='POST', | |
|
1081 | renderer='string_html', xhr=True) | |
|
1082 | def pullrequest_drafts(self): | |
|
1083 | self.load_default_context() | |
|
1084 | ||
|
1085 | pull_request = PullRequest.get_or_404( | |
|
1086 | self.request.matchdict['pull_request_id']) | |
|
1087 | pull_request_id = pull_request.pull_request_id | |
|
1088 | version = self.request.GET.get('version') | |
|
1089 | ||
|
1090 | _render = self.request.get_partial_renderer( | |
|
1091 | 'rhodecode:templates/base/sidebar.mako') | |
|
1092 | c = _render.get_call_context() | |
|
1093 | ||
|
1094 | (pull_request_latest, | |
|
1095 | pull_request_at_ver, | |
|
1096 | pull_request_display_obj, | |
|
1097 | at_version) = PullRequestModel().get_pr_version( | |
|
1098 | pull_request_id, version=version) | |
|
1099 | versions = pull_request_display_obj.versions() | |
|
1100 | latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest) | |
|
1101 | c.versions = versions + [latest_ver] | |
|
1102 | ||
|
1103 | c.at_version = at_version | |
|
1104 | c.at_version_num = (at_version | |
|
1105 | if at_version and at_version != PullRequest.LATEST_VER | |
|
1106 | else None) | |
|
1107 | ||
|
1108 | c.draft_comments = CommentsModel() \ | |
|
1109 | .get_pull_request_drafts(self._rhodecode_db_user.user_id, pull_request) | |
|
1110 | ||
|
1111 | all_comments = c.draft_comments | |
|
1112 | ||
|
1113 | existing_ids = self.get_comment_ids(self.request.POST) | |
|
1114 | return _render('comments_table', all_comments, len(all_comments), | |
|
1115 | existing_ids=existing_ids, draft_comments=True) | |
|
1116 | ||
|
1117 | @LoginRequired() | |
|
1118 | @NotAnonymous() | |
|
1119 | @HasRepoPermissionAnyDecorator( | |
|
1120 | 'repository.read', 'repository.write', 'repository.admin') | |
|
1074 | 1121 | @CSRFRequired() |
|
1075 | 1122 | @view_config( |
|
1076 | 1123 | route_name='pullrequest_create', request_method='POST', |
@@ -37,7 +37,7 b' from rhodecode.lib.exceptions import Com' | |||
|
37 | 37 | from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int |
|
38 | 38 | from rhodecode.model import BaseModel |
|
39 | 39 | from rhodecode.model.db import ( |
|
40 | false, | |
|
40 | false, true, | |
|
41 | 41 | ChangesetComment, |
|
42 | 42 | User, |
|
43 | 43 | Notification, |
@@ -201,6 +201,13 b' class CommentsModel(BaseModel):' | |||
|
201 | 201 | |
|
202 | 202 | return todos |
|
203 | 203 | |
|
204 | def get_pull_request_drafts(self, user_id, pull_request): | |
|
205 | drafts = Session().query(ChangesetComment) \ | |
|
206 | .filter(ChangesetComment.pull_request == pull_request) \ | |
|
207 | .filter(ChangesetComment.user_id == user_id) \ | |
|
208 | .filter(ChangesetComment.draft == true()) | |
|
209 | return drafts.all() | |
|
210 | ||
|
204 | 211 | def get_commit_unresolved_todos(self, commit_id, show_outdated=True, include_drafts=True): |
|
205 | 212 | |
|
206 | 213 | todos = Session().query(ChangesetComment) \ |
@@ -248,6 +248,7 b' function registerRCRoutes() {' | |||
|
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 | 249 | pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']); |
|
250 | 250 | pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']); |
|
251 | pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']); | |
|
251 | 252 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
252 | 253 | pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); |
|
253 | 254 | pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']); |
@@ -730,6 +730,10 b' var CommentsController = function() {' | |||
|
730 | 730 | // if we have this handler, run it, and refresh all comments boxes |
|
731 | 731 | refreshAllComments() |
|
732 | 732 | } |
|
733 | else if (window.refreshDraftComments !== undefined && isDraft) { | |
|
734 | // if we have this handler, run it, and refresh all comments boxes | |
|
735 | refreshDraftComments(); | |
|
736 | } | |
|
733 | 737 | return false; |
|
734 | 738 | }; |
|
735 | 739 | |
@@ -796,7 +800,7 b' var CommentsController = function() {' | |||
|
796 | 800 | |
|
797 | 801 | } |
|
798 | 802 | |
|
799 | this.finalizeDrafts = function(commentIds) { | |
|
803 | this.finalizeDrafts = function(commentIds, callback) { | |
|
800 | 804 | |
|
801 | 805 | SwalNoAnimation.fire({ |
|
802 | 806 | title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length), |
@@ -806,6 +810,9 b' var CommentsController = function() {' | |||
|
806 | 810 | |
|
807 | 811 | }).then(function(result) { |
|
808 | 812 | if (result.value) { |
|
813 | if (callback !== undefined) { | |
|
814 | callback(result) | |
|
815 | } | |
|
809 | 816 | self._finalizeDrafts(commentIds); |
|
810 | 817 | } |
|
811 | 818 | }) |
@@ -1220,6 +1227,10 b' var CommentsController = function() {' | |||
|
1220 | 1227 | // if we have this handler, run it, and refresh all comments boxes |
|
1221 | 1228 | refreshAllComments() |
|
1222 | 1229 | } |
|
1230 | else if (window.refreshDraftComments !== undefined && isDraft) { | |
|
1231 | // if we have this handler, run it, and refresh all comments boxes | |
|
1232 | refreshDraftComments(); | |
|
1233 | } | |
|
1223 | 1234 | |
|
1224 | 1235 | commentForm.setActionButtonsDisabled(false); |
|
1225 | 1236 | |
@@ -1415,6 +1426,10 b' var CommentsController = function() {' | |||
|
1415 | 1426 | // if we have this handler, run it, and refresh all comments boxes |
|
1416 | 1427 | refreshAllComments() |
|
1417 | 1428 | } |
|
1429 | else if (window.refreshDraftComments !== undefined && isDraft) { | |
|
1430 | // if we have this handler, run it, and refresh all comments boxes | |
|
1431 | refreshDraftComments(); | |
|
1432 | } | |
|
1418 | 1433 | |
|
1419 | 1434 | commentForm.setActionButtonsDisabled(false); |
|
1420 | 1435 |
@@ -1036,6 +1036,30 b' window.ReviewerPresenceController = func' | |||
|
1036 | 1036 | |
|
1037 | 1037 | }; |
|
1038 | 1038 | |
|
1039 | window.refreshCommentsSuccess = function(targetNode, counterNode, extraCallback) { | |
|
1040 | var $targetElem = targetNode; | |
|
1041 | var $counterElem = counterNode; | |
|
1042 | ||
|
1043 | return function (data) { | |
|
1044 | var newCount = $(data).data('counter'); | |
|
1045 | if (newCount !== undefined) { | |
|
1046 | var callback = function () { | |
|
1047 | $counterElem.animate({'opacity': 1.00}, 200) | |
|
1048 | $counterElem.html(newCount); | |
|
1049 | }; | |
|
1050 | $counterElem.animate({'opacity': 0.15}, 200, callback); | |
|
1051 | } | |
|
1052 | ||
|
1053 | $targetElem.css('opacity', 1); | |
|
1054 | $targetElem.html(data); | |
|
1055 | tooltipActivate(); | |
|
1056 | ||
|
1057 | if (extraCallback !== undefined) { | |
|
1058 | extraCallback(data) | |
|
1059 | } | |
|
1060 | } | |
|
1061 | } | |
|
1062 | ||
|
1039 | 1063 | window.refreshComments = function (version) { |
|
1040 | 1064 | version = version || templateContext.pull_request_data.pull_request_version || ''; |
|
1041 | 1065 | |
@@ -1060,23 +1084,8 b' window.refreshComments = function (versi' | |||
|
1060 | 1084 | |
|
1061 | 1085 | var $targetElem = $('.comments-content-table'); |
|
1062 | 1086 | $targetElem.css('opacity', 0.3); |
|
1063 | ||
|
1064 | var success = function (data) { | |
|
1065 | 1087 |
|
|
1066 | var newCount = $(data).data('counter'); | |
|
1067 | if (newCount !== undefined) { | |
|
1068 | var callback = function () { | |
|
1069 | $counterElem.animate({'opacity': 1.00}, 200) | |
|
1070 | $counterElem.html(newCount); | |
|
1071 | }; | |
|
1072 | $counterElem.animate({'opacity': 0.15}, 200, callback); | |
|
1073 | } | |
|
1074 | ||
|
1075 | $targetElem.css('opacity', 1); | |
|
1076 | $targetElem.html(data); | |
|
1077 | tooltipActivate(); | |
|
1078 | } | |
|
1079 | ||
|
1088 | var success = refreshCommentsSuccess($targetElem, $counterElem); | |
|
1080 | 1089 | ajaxPOST(loadUrl, data, success, null, {}) |
|
1081 | 1090 | |
|
1082 | 1091 | } |
@@ -1104,27 +1113,46 b' window.refreshTODOs = function (version)' | |||
|
1104 | 1113 | var data = {"comments": currentIDs}; |
|
1105 | 1114 | var $targetElem = $('.todos-content-table'); |
|
1106 | 1115 | $targetElem.css('opacity', 0.3); |
|
1107 | ||
|
1108 | var success = function (data) { | |
|
1109 | var $counterElem = $('#todos-count') | |
|
1110 | var newCount = $(data).data('counter'); | |
|
1111 | if (newCount !== undefined) { | |
|
1112 | var callback = function () { | |
|
1113 | $counterElem.animate({'opacity': 1.00}, 200) | |
|
1114 | $counterElem.html(newCount); | |
|
1115 | }; | |
|
1116 | $counterElem.animate({'opacity': 0.15}, 200, callback); | |
|
1117 | } | |
|
1118 | ||
|
1119 | $targetElem.css('opacity', 1); | |
|
1120 | $targetElem.html(data); | |
|
1121 | tooltipActivate(); | |
|
1122 | } | |
|
1116 | var $counterElem = $('#todos-count'); | |
|
1117 | var success = refreshCommentsSuccess($targetElem, $counterElem); | |
|
1123 | 1118 | |
|
1124 | 1119 | ajaxPOST(loadUrl, data, success, null, {}) |
|
1125 | 1120 | |
|
1126 | 1121 | } |
|
1127 | 1122 | |
|
1123 | window.refreshDraftComments = function () { | |
|
1124 | ||
|
1125 | // Pull request case | |
|
1126 | if (templateContext.pull_request_data.pull_request_id !== null) { | |
|
1127 | var params = { | |
|
1128 | 'pull_request_id': templateContext.pull_request_data.pull_request_id, | |
|
1129 | 'repo_name': templateContext.repo_name, | |
|
1130 | }; | |
|
1131 | var loadUrl = pyroutes.url('pullrequest_drafts', params); | |
|
1132 | } // commit case | |
|
1133 | else { | |
|
1134 | return | |
|
1135 | } | |
|
1136 | ||
|
1137 | var data = {}; | |
|
1138 | ||
|
1139 | var $targetElem = $('.drafts-content-table'); | |
|
1140 | $targetElem.css('opacity', 0.3); | |
|
1141 | var $counterElem = $('#drafts-count'); | |
|
1142 | var extraCallback = function(data) { | |
|
1143 | if ($(data).data('counter') == 0){ | |
|
1144 | $('#draftsTable').hide(); | |
|
1145 | } else { | |
|
1146 | $('#draftsTable').show(); | |
|
1147 | } | |
|
1148 | // uncheck on load the select all checkbox | |
|
1149 | $('[name=select_all_drafts]').prop('checked', 0); | |
|
1150 | } | |
|
1151 | var success = refreshCommentsSuccess($targetElem, $counterElem, extraCallback); | |
|
1152 | ||
|
1153 | ajaxPOST(loadUrl, data, success, null, {}) | |
|
1154 | }; | |
|
1155 | ||
|
1128 | 1156 | window.refreshAllComments = function (version) { |
|
1129 | 1157 | version = version || templateContext.pull_request_data.pull_request_version || ''; |
|
1130 | 1158 | |
@@ -1132,10 +1160,6 b' window.refreshAllComments = function (ve' | |||
|
1132 | 1160 | refreshTODOs(version); |
|
1133 | 1161 | }; |
|
1134 | 1162 | |
|
1135 | window.refreshDraftComments = function () { | |
|
1136 | alert('TODO: refresh Draft Comments needs implementation') | |
|
1137 | }; | |
|
1138 | ||
|
1139 | 1163 | window.sidebarComment = function (commentId) { |
|
1140 | 1164 | var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64'); |
|
1141 | 1165 | if (!jsonData) { |
@@ -4,7 +4,7 b'' | |||
|
4 | 4 | ## ${sidebar.comments_table()} |
|
5 | 5 | <%namespace name="base" file="/base/base.mako"/> |
|
6 | 6 | |
|
7 | <%def name="comments_table(comments, counter_num, todo_comments=False, existing_ids=None, is_pr=True)"> | |
|
7 | <%def name="comments_table(comments, counter_num, todo_comments=False, draft_comments=False, existing_ids=None, is_pr=True)"> | |
|
8 | 8 | <% |
|
9 | 9 | if todo_comments: |
|
10 | 10 | cls_ = 'todos-content-table' |
@@ -15,10 +15,13 b'' | |||
|
15 | 15 | # own comments first |
|
16 | 16 | user_id = 0 |
|
17 | 17 | return '{}'.format(str(entry.comment_id).zfill(10000)) |
|
18 | elif draft_comments: | |
|
19 | cls_ = 'drafts-content-table' | |
|
20 | def sorter(entry): | |
|
21 | return '{}'.format(str(entry.comment_id).zfill(10000)) | |
|
18 | 22 | else: |
|
19 | 23 | cls_ = 'comments-content-table' |
|
20 | 24 | def sorter(entry): |
|
21 | user_id = entry.author.user_id | |
|
22 | 25 | return '{}'.format(str(entry.comment_id).zfill(10000)) |
|
23 | 26 | |
|
24 | 27 | existing_ids = existing_ids or [] |
@@ -32,7 +35,7 b'' | |||
|
32 | 35 | display = '' |
|
33 | 36 | _cls = '' |
|
34 | 37 | ## Extra precaution to not show drafts in the sidebar for todo/comments |
|
35 | if comment_obj.draft: | |
|
38 | if comment_obj.draft and not draft_comments: | |
|
36 | 39 | continue |
|
37 | 40 | %> |
|
38 | 41 | |
@@ -87,6 +90,11 b'' | |||
|
87 | 90 | % endif |
|
88 | 91 | |
|
89 | 92 | <tr class="${_cls}" style="display: ${display};" data-sidebar-comment-id="${comment_obj.comment_id}"> |
|
93 | % if draft_comments: | |
|
94 | <td style="width: 15px;"> | |
|
95 | ${h.checkbox('submit_draft', id=None, value=comment_obj.comment_id)} | |
|
96 | </td> | |
|
97 | % endif | |
|
90 | 98 | <td class="td-todo-number"> |
|
91 | 99 | <% |
|
92 | 100 | version_info = '' |
@@ -552,28 +552,35 b'' | |||
|
552 | 552 | |
|
553 | 553 | ## Drafts |
|
554 | 554 | % if c.rhodecode_edition_id == 'EE': |
|
555 | <div class="sidebar-element clear-both"> | |
|
556 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Drafts')}"> | |
|
555 | <div id="draftsTable" class="sidebar-element clear-both" style="display: ${'block' if c.draft_comments else 'none'}"> | |
|
556 | <div class="tooltip right-sidebar-collapsed-state" style="display: none;" onclick="toggleSidebar(); return false" title="${_('Drafts')}"> | |
|
557 | 557 | <i class="icon-comment icon-draft"></i> |
|
558 |
<span id=" |
|
|
558 | <span id="drafts-count">${len(c.draft_comments)}</span> | |
|
559 | 559 | </div> |
|
560 | 560 | |
|
561 | 561 | <div class="right-sidebar-expanded-state pr-details-title"> |
|
562 |
<span |
|
|
562 | <span style="padding-left: 2px"> | |
|
563 | <input name="select_all_drafts" type="checkbox" onclick="$('[name=submit_draft]').prop('checked', !$('[name=submit_draft]').prop('checked'))"> | |
|
564 | </span> | |
|
565 | <span class="sidebar-heading noselect" onclick="refreshDraftComments(); return false"> | |
|
563 | 566 | <i class="icon-comment icon-draft"></i> |
|
564 | 567 | ${_('Drafts')} |
|
565 | 568 | </span> |
|
569 | <span class="block-right action_button last-item" onclick="submitDrafts(event)">${_('Submit')}</span> | |
|
566 | 570 | </div> |
|
567 | 571 | |
|
568 | 572 | <div id="drafts" class="right-sidebar-expanded-state pr-details-content reviewers"> |
|
569 | ## members redering block | |
|
570 | ||
|
571 | ||
|
572 | ??? | |
|
573 | ||
|
574 | ||
|
575 | ## end members redering block | |
|
576 | ||
|
573 | % if c.draft_comments: | |
|
574 | ${sidebar.comments_table(c.draft_comments, len(c.draft_comments), draft_comments=True)} | |
|
575 | % else: | |
|
576 | <table class="drafts-content-table"> | |
|
577 | <tr> | |
|
578 | <td> | |
|
579 | ${_('No TODOs yet')} | |
|
580 | </td> | |
|
581 | </tr> | |
|
582 | </table> | |
|
583 | % endif | |
|
577 | 584 | </div> |
|
578 | 585 | |
|
579 | 586 | </div> |
@@ -705,7 +712,7 b'' | |||
|
705 | 712 | % endif |
|
706 | 713 | |
|
707 | 714 | ## TODOs |
|
708 | <div class="sidebar-element clear-both"> | |
|
715 | <div id="todosTable" class="sidebar-element clear-both"> | |
|
709 | 716 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs"> |
|
710 | 717 | <i class="icon-flag-filled"></i> |
|
711 | 718 | <span id="todos-count">${len(c.unresolved_comments)}</span> |
@@ -739,7 +746,7 b'' | |||
|
739 | 746 | % if c.unresolved_comments + c.resolved_comments: |
|
740 | 747 | ${sidebar.comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)} |
|
741 | 748 | % else: |
|
742 | <table> | |
|
749 | <table class="todos-content-table"> | |
|
743 | 750 | <tr> |
|
744 | 751 | <td> |
|
745 | 752 | ${_('No TODOs yet')} |
@@ -752,7 +759,7 b'' | |||
|
752 | 759 | </div> |
|
753 | 760 | |
|
754 | 761 | ## COMMENTS |
|
755 | <div class="sidebar-element clear-both"> | |
|
762 | <div id="commentsTable" class="sidebar-element clear-both"> | |
|
756 | 763 | <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}"> |
|
757 | 764 | <i class="icon-comment" style="color: #949494"></i> |
|
758 | 765 | <span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span> |
@@ -790,7 +797,7 b'' | |||
|
790 | 797 | % if c.inline_comments_flat + c.comments: |
|
791 | 798 | ${sidebar.comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))} |
|
792 | 799 | % else: |
|
793 | <table> | |
|
800 | <table class="comments-content-table"> | |
|
794 | 801 | <tr> |
|
795 | 802 | <td> |
|
796 | 803 | ${_('No Comments yet')} |
@@ -919,6 +926,23 b' window.setObserversData = ${c.pull_reque' | |||
|
919 | 926 | ); |
|
920 | 927 | }; |
|
921 | 928 | |
|
929 | window.submitDrafts = function (event) { | |
|
930 | var target = $(event.currentTarget); | |
|
931 | var callback = function (result) { | |
|
932 | target.removeAttr('onclick').html('saving...'); | |
|
933 | } | |
|
934 | var draftIds = []; | |
|
935 | $.each($('[name=submit_draft]:checked'), function (idx, val) { | |
|
936 | draftIds.push(parseInt($(val).val())); | |
|
937 | }) | |
|
938 | if (draftIds.length > 0) { | |
|
939 | Rhodecode.comments.finalizeDrafts(draftIds, callback); | |
|
940 | } | |
|
941 | else { | |
|
942 | ||
|
943 | } | |
|
944 | } | |
|
945 | ||
|
922 | 946 | window.closePullRequest = function (status) { |
|
923 | 947 | if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) { |
|
924 | 948 | return false; |
@@ -1026,7 +1050,6 b' window.setObserversData = ${c.pull_reque' | |||
|
1026 | 1050 | new ReviewerPresenceController(channel) |
|
1027 | 1051 | // register globally so inject comment logic can re-use it. |
|
1028 | 1052 | window.commentsController = commentsController; |
|
1029 | ||
|
1030 | 1053 | }) |
|
1031 | 1054 | </script> |
|
1032 | 1055 |
General Comments 0
You need to be logged in to leave comments.
Login now