##// END OF EJS Templates
drafts: sidebar functionality
milka -
r4562:20bc1204 default
parent child Browse files
Show More
@@ -355,6 +355,11 b' def includeme(config):'
355 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos',
355 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos',
356 repo_route=True)
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 # Artifacts, (EE feature)
363 # Artifacts, (EE feature)
359 config.add_route(
364 config.add_route(
360 name='repo_artifacts_list',
365 name='repo_artifacts_list',
@@ -501,6 +501,11 b' class RepoPullRequestsView(RepoAppView, '
501 c.resolved_comments = CommentsModel() \
501 c.resolved_comments = CommentsModel() \
502 .get_pull_request_resolved_todos(pull_request_latest)
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 # if we use version, then do not show later comments
509 # if we use version, then do not show later comments
505 # than current version
510 # than current version
506 display_inline_comments = collections.defaultdict(
511 display_inline_comments = collections.defaultdict(
@@ -1071,6 +1076,48 b' class RepoPullRequestsView(RepoAppView, '
1071 @NotAnonymous()
1076 @NotAnonymous()
1072 @HasRepoPermissionAnyDecorator(
1077 @HasRepoPermissionAnyDecorator(
1073 'repository.read', 'repository.write', 'repository.admin')
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 @CSRFRequired()
1121 @CSRFRequired()
1075 @view_config(
1122 @view_config(
1076 route_name='pullrequest_create', request_method='POST',
1123 route_name='pullrequest_create', request_method='POST',
@@ -37,7 +37,7 b' from rhodecode.lib.exceptions import Com'
37 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int
37 from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import (
39 from rhodecode.model.db import (
40 false,
40 false, true,
41 ChangesetComment,
41 ChangesetComment,
42 User,
42 User,
43 Notification,
43 Notification,
@@ -201,6 +201,13 b' class CommentsModel(BaseModel):'
201
201
202 return todos
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 def get_commit_unresolved_todos(self, commit_id, show_outdated=True, include_drafts=True):
211 def get_commit_unresolved_todos(self, commit_id, show_outdated=True, include_drafts=True):
205
212
206 todos = Session().query(ChangesetComment) \
213 todos = Session().query(ChangesetComment) \
@@ -248,6 +248,7 b' function registerRCRoutes() {'
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']);
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']);
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']);
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 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
252 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
252 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
253 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
253 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
254 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
@@ -730,6 +730,10 b' var CommentsController = function() {'
730 // if we have this handler, run it, and refresh all comments boxes
730 // if we have this handler, run it, and refresh all comments boxes
731 refreshAllComments()
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 return false;
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 SwalNoAnimation.fire({
805 SwalNoAnimation.fire({
802 title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
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 }).then(function(result) {
811 }).then(function(result) {
808 if (result.value) {
812 if (result.value) {
813 if (callback !== undefined) {
814 callback(result)
815 }
809 self._finalizeDrafts(commentIds);
816 self._finalizeDrafts(commentIds);
810 }
817 }
811 })
818 })
@@ -1220,6 +1227,10 b' var CommentsController = function() {'
1220 // if we have this handler, run it, and refresh all comments boxes
1227 // if we have this handler, run it, and refresh all comments boxes
1221 refreshAllComments()
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 commentForm.setActionButtonsDisabled(false);
1235 commentForm.setActionButtonsDisabled(false);
1225
1236
@@ -1415,6 +1426,10 b' var CommentsController = function() {'
1415 // if we have this handler, run it, and refresh all comments boxes
1426 // if we have this handler, run it, and refresh all comments boxes
1416 refreshAllComments()
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 commentForm.setActionButtonsDisabled(false);
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 window.refreshComments = function (version) {
1063 window.refreshComments = function (version) {
1040 version = version || templateContext.pull_request_data.pull_request_version || '';
1064 version = version || templateContext.pull_request_data.pull_request_version || '';
1041
1065
@@ -1060,23 +1084,8 b' window.refreshComments = function (versi'
1060
1084
1061 var $targetElem = $('.comments-content-table');
1085 var $targetElem = $('.comments-content-table');
1062 $targetElem.css('opacity', 0.3);
1086 $targetElem.css('opacity', 0.3);
1063
1087 var $counterElem = $('#comments-count');
1064 var success = function (data) {
1088 var success = refreshCommentsSuccess($targetElem, $counterElem);
1065 var $counterElem = $('#comments-count');
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
1080 ajaxPOST(loadUrl, data, success, null, {})
1089 ajaxPOST(loadUrl, data, success, null, {})
1081
1090
1082 }
1091 }
@@ -1104,27 +1113,46 b' window.refreshTODOs = function (version)'
1104 var data = {"comments": currentIDs};
1113 var data = {"comments": currentIDs};
1105 var $targetElem = $('.todos-content-table');
1114 var $targetElem = $('.todos-content-table');
1106 $targetElem.css('opacity', 0.3);
1115 $targetElem.css('opacity', 0.3);
1107
1116 var $counterElem = $('#todos-count');
1108 var success = function (data) {
1117 var success = refreshCommentsSuccess($targetElem, $counterElem);
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 }
1123
1118
1124 ajaxPOST(loadUrl, data, success, null, {})
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 window.refreshAllComments = function (version) {
1156 window.refreshAllComments = function (version) {
1129 version = version || templateContext.pull_request_data.pull_request_version || '';
1157 version = version || templateContext.pull_request_data.pull_request_version || '';
1130
1158
@@ -1132,10 +1160,6 b' window.refreshAllComments = function (ve'
1132 refreshTODOs(version);
1160 refreshTODOs(version);
1133 };
1161 };
1134
1162
1135 window.refreshDraftComments = function () {
1136 alert('TODO: refresh Draft Comments needs implementation')
1137 };
1138
1139 window.sidebarComment = function (commentId) {
1163 window.sidebarComment = function (commentId) {
1140 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1164 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1141 if (!jsonData) {
1165 if (!jsonData) {
@@ -4,7 +4,7 b''
4 ## ${sidebar.comments_table()}
4 ## ${sidebar.comments_table()}
5 <%namespace name="base" file="/base/base.mako"/>
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 if todo_comments:
9 if todo_comments:
10 cls_ = 'todos-content-table'
10 cls_ = 'todos-content-table'
@@ -15,10 +15,13 b''
15 # own comments first
15 # own comments first
16 user_id = 0
16 user_id = 0
17 return '{}'.format(str(entry.comment_id).zfill(10000))
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 else:
22 else:
19 cls_ = 'comments-content-table'
23 cls_ = 'comments-content-table'
20 def sorter(entry):
24 def sorter(entry):
21 user_id = entry.author.user_id
22 return '{}'.format(str(entry.comment_id).zfill(10000))
25 return '{}'.format(str(entry.comment_id).zfill(10000))
23
26
24 existing_ids = existing_ids or []
27 existing_ids = existing_ids or []
@@ -32,7 +35,7 b''
32 display = ''
35 display = ''
33 _cls = ''
36 _cls = ''
34 ## Extra precaution to not show drafts in the sidebar for todo/comments
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 continue
39 continue
37 %>
40 %>
38
41
@@ -87,6 +90,11 b''
87 % endif
90 % endif
88
91
89 <tr class="${_cls}" style="display: ${display};" data-sidebar-comment-id="${comment_obj.comment_id}">
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 <td class="td-todo-number">
98 <td class="td-todo-number">
91 <%
99 <%
92 version_info = ''
100 version_info = ''
@@ -552,28 +552,35 b''
552
552
553 ## Drafts
553 ## Drafts
554 % if c.rhodecode_edition_id == 'EE':
554 % if c.rhodecode_edition_id == 'EE':
555 <div class="sidebar-element clear-both">
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')}">
556 <div class="tooltip right-sidebar-collapsed-state" style="display: none;" onclick="toggleSidebar(); return false" title="${_('Drafts')}">
557 <i class="icon-comment icon-draft"></i>
557 <i class="icon-comment icon-draft"></i>
558 <span id="comments-count">${0}</span>
558 <span id="drafts-count">${len(c.draft_comments)}</span>
559 </div>
559 </div>
560
560
561 <div class="right-sidebar-expanded-state pr-details-title">
561 <div class="right-sidebar-expanded-state pr-details-title">
562 <span class="sidebar-heading noselect">
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 <i class="icon-comment icon-draft"></i>
566 <i class="icon-comment icon-draft"></i>
564 ${_('Drafts')}
567 ${_('Drafts')}
565 </span>
568 </span>
569 <span class="block-right action_button last-item" onclick="submitDrafts(event)">${_('Submit')}</span>
566 </div>
570 </div>
567
571
568 <div id="drafts" class="right-sidebar-expanded-state pr-details-content reviewers">
572 <div id="drafts" class="right-sidebar-expanded-state pr-details-content reviewers">
569 ## members redering block
573 % if c.draft_comments:
570
574 ${sidebar.comments_table(c.draft_comments, len(c.draft_comments), draft_comments=True)}
571
575 % else:
572 ???
576 <table class="drafts-content-table">
573
577 <tr>
574
578 <td>
575 ## end members redering block
579 ${_('No TODOs yet')}
576
580 </td>
581 </tr>
582 </table>
583 % endif
577 </div>
584 </div>
578
585
579 </div>
586 </div>
@@ -705,7 +712,7 b''
705 % endif
712 % endif
706
713
707 ## TODOs
714 ## TODOs
708 <div class="sidebar-element clear-both">
715 <div id="todosTable" class="sidebar-element clear-both">
709 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs">
716 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs">
710 <i class="icon-flag-filled"></i>
717 <i class="icon-flag-filled"></i>
711 <span id="todos-count">${len(c.unresolved_comments)}</span>
718 <span id="todos-count">${len(c.unresolved_comments)}</span>
@@ -739,7 +746,7 b''
739 % if c.unresolved_comments + c.resolved_comments:
746 % if c.unresolved_comments + c.resolved_comments:
740 ${sidebar.comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)}
747 ${sidebar.comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)}
741 % else:
748 % else:
742 <table>
749 <table class="todos-content-table">
743 <tr>
750 <tr>
744 <td>
751 <td>
745 ${_('No TODOs yet')}
752 ${_('No TODOs yet')}
@@ -752,7 +759,7 b''
752 </div>
759 </div>
753
760
754 ## COMMENTS
761 ## COMMENTS
755 <div class="sidebar-element clear-both">
762 <div id="commentsTable" class="sidebar-element clear-both">
756 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}">
763 <div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}">
757 <i class="icon-comment" style="color: #949494"></i>
764 <i class="icon-comment" style="color: #949494"></i>
758 <span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span>
765 <span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span>
@@ -790,7 +797,7 b''
790 % if c.inline_comments_flat + c.comments:
797 % if c.inline_comments_flat + c.comments:
791 ${sidebar.comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))}
798 ${sidebar.comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))}
792 % else:
799 % else:
793 <table>
800 <table class="comments-content-table">
794 <tr>
801 <tr>
795 <td>
802 <td>
796 ${_('No Comments yet')}
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 window.closePullRequest = function (status) {
946 window.closePullRequest = function (status) {
923 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
947 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
924 return false;
948 return false;
@@ -1026,7 +1050,6 b' window.setObserversData = ${c.pull_reque'
1026 new ReviewerPresenceController(channel)
1050 new ReviewerPresenceController(channel)
1027 // register globally so inject comment logic can re-use it.
1051 // register globally so inject comment logic can re-use it.
1028 window.commentsController = commentsController;
1052 window.commentsController = commentsController;
1029
1030 })
1053 })
1031 </script>
1054 </script>
1032
1055
General Comments 0
You need to be logged in to leave comments. Login now