diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py --- a/rhodecode/apps/repository/__init__.py +++ b/rhodecode/apps/repository/__init__.py @@ -355,6 +355,11 @@ def includeme(config): pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos', repo_route=True) + config.add_route( + name='pullrequest_drafts', + pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/drafts', + repo_route=True) + # Artifacts, (EE feature) config.add_route( name='repo_artifacts_list', diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py --- a/rhodecode/apps/repository/views/repo_pull_requests.py +++ b/rhodecode/apps/repository/views/repo_pull_requests.py @@ -501,6 +501,11 @@ class RepoPullRequestsView(RepoAppView, c.resolved_comments = CommentsModel() \ .get_pull_request_resolved_todos(pull_request_latest) + # Drafts + c.draft_comments = CommentsModel().get_pull_request_drafts( + self._rhodecode_db_user.user_id, + pull_request_latest) + # if we use version, then do not show later comments # than current version display_inline_comments = collections.defaultdict( @@ -1071,6 +1076,48 @@ class RepoPullRequestsView(RepoAppView, @NotAnonymous() @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') + @view_config( + route_name='pullrequest_drafts', request_method='POST', + renderer='string_html', xhr=True) + def pullrequest_drafts(self): + self.load_default_context() + + pull_request = PullRequest.get_or_404( + self.request.matchdict['pull_request_id']) + pull_request_id = pull_request.pull_request_id + version = self.request.GET.get('version') + + _render = self.request.get_partial_renderer( + 'rhodecode:templates/base/sidebar.mako') + c = _render.get_call_context() + + (pull_request_latest, + pull_request_at_ver, + pull_request_display_obj, + at_version) = PullRequestModel().get_pr_version( + pull_request_id, version=version) + versions = pull_request_display_obj.versions() + latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest) + c.versions = versions + [latest_ver] + + c.at_version = at_version + c.at_version_num = (at_version + if at_version and at_version != PullRequest.LATEST_VER + else None) + + c.draft_comments = CommentsModel() \ + .get_pull_request_drafts(self._rhodecode_db_user.user_id, pull_request) + + all_comments = c.draft_comments + + existing_ids = self.get_comment_ids(self.request.POST) + return _render('comments_table', all_comments, len(all_comments), + existing_ids=existing_ids, draft_comments=True) + + @LoginRequired() + @NotAnonymous() + @HasRepoPermissionAnyDecorator( + 'repository.read', 'repository.write', 'repository.admin') @CSRFRequired() @view_config( route_name='pullrequest_create', request_method='POST', diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py --- a/rhodecode/model/comment.py +++ b/rhodecode/model/comment.py @@ -37,7 +37,7 @@ from rhodecode.lib.exceptions import Com from rhodecode.lib.utils2 import extract_mentioned_users, safe_str, safe_int from rhodecode.model import BaseModel from rhodecode.model.db import ( - false, + false, true, ChangesetComment, User, Notification, @@ -201,6 +201,13 @@ class CommentsModel(BaseModel): return todos + def get_pull_request_drafts(self, user_id, pull_request): + drafts = Session().query(ChangesetComment) \ + .filter(ChangesetComment.pull_request == pull_request) \ + .filter(ChangesetComment.user_id == user_id) \ + .filter(ChangesetComment.draft == true()) + return drafts.all() + def get_commit_unresolved_todos(self, commit_id, show_outdated=True, include_drafts=True): todos = Session().query(ChangesetComment) \ diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -248,6 +248,7 @@ function registerRCRoutes() { 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']); pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']); pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']); + pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']); pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']); diff --git a/rhodecode/public/js/src/rhodecode/comments.js b/rhodecode/public/js/src/rhodecode/comments.js --- a/rhodecode/public/js/src/rhodecode/comments.js +++ b/rhodecode/public/js/src/rhodecode/comments.js @@ -730,6 +730,10 @@ var CommentsController = function() { // if we have this handler, run it, and refresh all comments boxes refreshAllComments() } + else if (window.refreshDraftComments !== undefined && isDraft) { + // if we have this handler, run it, and refresh all comments boxes + refreshDraftComments(); + } return false; }; @@ -796,7 +800,7 @@ var CommentsController = function() { } - this.finalizeDrafts = function(commentIds) { + this.finalizeDrafts = function(commentIds, callback) { SwalNoAnimation.fire({ title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length), @@ -806,6 +810,9 @@ var CommentsController = function() { }).then(function(result) { if (result.value) { + if (callback !== undefined) { + callback(result) + } self._finalizeDrafts(commentIds); } }) @@ -1220,6 +1227,10 @@ var CommentsController = function() { // if we have this handler, run it, and refresh all comments boxes refreshAllComments() } + else if (window.refreshDraftComments !== undefined && isDraft) { + // if we have this handler, run it, and refresh all comments boxes + refreshDraftComments(); + } commentForm.setActionButtonsDisabled(false); @@ -1415,6 +1426,10 @@ var CommentsController = function() { // if we have this handler, run it, and refresh all comments boxes refreshAllComments() } + else if (window.refreshDraftComments !== undefined && isDraft) { + // if we have this handler, run it, and refresh all comments boxes + refreshDraftComments(); + } commentForm.setActionButtonsDisabled(false); diff --git a/rhodecode/public/js/src/rhodecode/pullrequests.js b/rhodecode/public/js/src/rhodecode/pullrequests.js --- a/rhodecode/public/js/src/rhodecode/pullrequests.js +++ b/rhodecode/public/js/src/rhodecode/pullrequests.js @@ -1036,6 +1036,30 @@ window.ReviewerPresenceController = func }; +window.refreshCommentsSuccess = function(targetNode, counterNode, extraCallback) { + var $targetElem = targetNode; + var $counterElem = counterNode; + + return function (data) { + var newCount = $(data).data('counter'); + if (newCount !== undefined) { + var callback = function () { + $counterElem.animate({'opacity': 1.00}, 200) + $counterElem.html(newCount); + }; + $counterElem.animate({'opacity': 0.15}, 200, callback); + } + + $targetElem.css('opacity', 1); + $targetElem.html(data); + tooltipActivate(); + + if (extraCallback !== undefined) { + extraCallback(data) + } + } +} + window.refreshComments = function (version) { version = version || templateContext.pull_request_data.pull_request_version || ''; @@ -1060,23 +1084,8 @@ window.refreshComments = function (versi var $targetElem = $('.comments-content-table'); $targetElem.css('opacity', 0.3); - - var success = function (data) { - var $counterElem = $('#comments-count'); - var newCount = $(data).data('counter'); - if (newCount !== undefined) { - var callback = function () { - $counterElem.animate({'opacity': 1.00}, 200) - $counterElem.html(newCount); - }; - $counterElem.animate({'opacity': 0.15}, 200, callback); - } - - $targetElem.css('opacity', 1); - $targetElem.html(data); - tooltipActivate(); - } - + var $counterElem = $('#comments-count'); + var success = refreshCommentsSuccess($targetElem, $counterElem); ajaxPOST(loadUrl, data, success, null, {}) } @@ -1104,27 +1113,46 @@ window.refreshTODOs = function (version) var data = {"comments": currentIDs}; var $targetElem = $('.todos-content-table'); $targetElem.css('opacity', 0.3); - - var success = function (data) { - var $counterElem = $('#todos-count') - var newCount = $(data).data('counter'); - if (newCount !== undefined) { - var callback = function () { - $counterElem.animate({'opacity': 1.00}, 200) - $counterElem.html(newCount); - }; - $counterElem.animate({'opacity': 0.15}, 200, callback); - } - - $targetElem.css('opacity', 1); - $targetElem.html(data); - tooltipActivate(); - } + var $counterElem = $('#todos-count'); + var success = refreshCommentsSuccess($targetElem, $counterElem); ajaxPOST(loadUrl, data, success, null, {}) } +window.refreshDraftComments = function () { + + // Pull request case + if (templateContext.pull_request_data.pull_request_id !== null) { + var params = { + 'pull_request_id': templateContext.pull_request_data.pull_request_id, + 'repo_name': templateContext.repo_name, + }; + var loadUrl = pyroutes.url('pullrequest_drafts', params); + } // commit case + else { + return + } + + var data = {}; + + var $targetElem = $('.drafts-content-table'); + $targetElem.css('opacity', 0.3); + var $counterElem = $('#drafts-count'); + var extraCallback = function(data) { + if ($(data).data('counter') == 0){ + $('#draftsTable').hide(); + } else { + $('#draftsTable').show(); + } + // uncheck on load the select all checkbox + $('[name=select_all_drafts]').prop('checked', 0); + } + var success = refreshCommentsSuccess($targetElem, $counterElem, extraCallback); + + ajaxPOST(loadUrl, data, success, null, {}) +}; + window.refreshAllComments = function (version) { version = version || templateContext.pull_request_data.pull_request_version || ''; @@ -1132,10 +1160,6 @@ window.refreshAllComments = function (ve refreshTODOs(version); }; -window.refreshDraftComments = function () { - alert('TODO: refresh Draft Comments needs implementation') -}; - window.sidebarComment = function (commentId) { var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64'); if (!jsonData) { diff --git a/rhodecode/templates/base/sidebar.mako b/rhodecode/templates/base/sidebar.mako --- a/rhodecode/templates/base/sidebar.mako +++ b/rhodecode/templates/base/sidebar.mako @@ -4,7 +4,7 @@ ## ${sidebar.comments_table()} <%namespace name="base" file="/base/base.mako"/> -<%def name="comments_table(comments, counter_num, todo_comments=False, existing_ids=None, is_pr=True)"> +<%def name="comments_table(comments, counter_num, todo_comments=False, draft_comments=False, existing_ids=None, is_pr=True)"> <% if todo_comments: cls_ = 'todos-content-table' @@ -15,10 +15,13 @@ # own comments first user_id = 0 return '{}'.format(str(entry.comment_id).zfill(10000)) + elif draft_comments: + cls_ = 'drafts-content-table' + def sorter(entry): + return '{}'.format(str(entry.comment_id).zfill(10000)) else: cls_ = 'comments-content-table' def sorter(entry): - user_id = entry.author.user_id return '{}'.format(str(entry.comment_id).zfill(10000)) existing_ids = existing_ids or [] @@ -32,7 +35,7 @@ display = '' _cls = '' ## Extra precaution to not show drafts in the sidebar for todo/comments - if comment_obj.draft: + if comment_obj.draft and not draft_comments: continue %> @@ -87,6 +90,11 @@ % endif + % if draft_comments: + + ${h.checkbox('submit_draft', id=None, value=comment_obj.comment_id)} + + % endif <% version_info = '' diff --git a/rhodecode/templates/pullrequests/pullrequest_show.mako b/rhodecode/templates/pullrequests/pullrequest_show.mako --- a/rhodecode/templates/pullrequests/pullrequest_show.mako +++ b/rhodecode/templates/pullrequests/pullrequest_show.mako @@ -552,28 +552,35 @@ ## Drafts % if c.rhodecode_edition_id == 'EE': -