diff --git a/rhodecode/controllers/pullrequests.py b/rhodecode/controllers/pullrequests.py --- a/rhodecode/controllers/pullrequests.py +++ b/rhodecode/controllers/pullrequests.py @@ -45,16 +45,17 @@ from rhodecode.lib.auth import ( from rhodecode.lib.channelstream import channelstream_request from rhodecode.lib.compat import OrderedDict from rhodecode.lib.utils import jsonify -from rhodecode.lib.utils2 import safe_int, safe_str, str2bool, safe_unicode +from rhodecode.lib.utils2 import ( + safe_int, safe_str, str2bool, safe_unicode, UnsafeAttributeDict) from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason from rhodecode.lib.vcs.exceptions import ( EmptyRepositoryError, CommitDoesNotExistError, RepositoryRequirementError, NodeDoesNotExistError) -from rhodecode.lib.diffs import LimitedDiffContainer + from rhodecode.model.changeset_status import ChangesetStatusModel from rhodecode.model.comment import ChangesetCommentsModel -from rhodecode.model.db import PullRequest, ChangesetStatus, ChangesetComment, \ - Repository +from rhodecode.model.db import (PullRequest, ChangesetStatus, ChangesetComment, + Repository, PullRequestVersion) from rhodecode.model.forms import PullRequestForm from rhodecode.model.meta import Session from rhodecode.model.pull_request import PullRequestModel @@ -675,46 +676,133 @@ class PullrequestsController(BaseRepoCon return redirect(url('my_account_pullrequests')) raise HTTPForbidden() + def _get_pr_version(self, pull_request_id, version=None): + pull_request_id = safe_int(pull_request_id) + at_version = None + if version: + pull_request_ver = PullRequestVersion.get_or_404(version) + pull_request_obj = pull_request_ver + _org_pull_request_obj = pull_request_ver.pull_request + at_version = pull_request_ver.pull_request_version_id + else: + _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404(pull_request_id) + + class PullRequestDisplay(object): + """ + Special object wrapper for showing PullRequest data via Versions + It mimics PR object as close as possible. This is read only object + just for display + """ + def __init__(self, attrs): + self.attrs = attrs + # internal have priority over the given ones via attrs + self.internal = ['versions'] + + def __getattr__(self, item): + if item in self.internal: + return getattr(self, item) + try: + return self.attrs[item] + except KeyError: + raise AttributeError( + '%s object has no attribute %s' % (self, item)) + + def versions(self): + return pull_request_obj.versions.order_by( + PullRequestVersion.pull_request_version_id).all() + + def is_closed(self): + return pull_request_obj.is_closed() + + attrs = UnsafeAttributeDict(pull_request_obj.get_api_data()) + + attrs.author = UnsafeAttributeDict( + pull_request_obj.author.get_api_data()) + if pull_request_obj.target_repo: + attrs.target_repo = UnsafeAttributeDict( + pull_request_obj.target_repo.get_api_data()) + attrs.target_repo.clone_url = pull_request_obj.target_repo.clone_url + + if pull_request_obj.source_repo: + attrs.source_repo = UnsafeAttributeDict( + pull_request_obj.source_repo.get_api_data()) + attrs.source_repo.clone_url = pull_request_obj.source_repo.clone_url + + attrs.source_ref_parts = pull_request_obj.source_ref_parts + attrs.target_ref_parts = pull_request_obj.target_ref_parts + + attrs.shadow_merge_ref = _org_pull_request_obj.shadow_merge_ref + + pull_request_ver = PullRequestDisplay(attrs) + + return _org_pull_request_obj, pull_request_obj, \ + pull_request_ver, at_version + @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def show(self, repo_name, pull_request_id): pull_request_id = safe_int(pull_request_id) - c.pull_request = PullRequest.get_or_404(pull_request_id) + + version = request.GET.get('version') + pull_request_latest, \ + pull_request, \ + pull_request_ver, \ + at_version = self._get_pr_version(pull_request_id, version=version) c.template_context['pull_request_data']['pull_request_id'] = \ pull_request_id # pull_requests repo_name we opened it against # ie. target_repo must match - if repo_name != c.pull_request.target_repo.repo_name: + if repo_name != pull_request.target_repo.repo_name: raise HTTPNotFound - c.allowed_to_change_status = PullRequestModel(). \ - check_user_change_status(c.pull_request, c.rhodecode_user) - c.allowed_to_update = PullRequestModel().check_user_update( - c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() - c.allowed_to_merge = PullRequestModel().check_user_merge( - c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( - c.pull_request) - c.allowed_to_delete = PullRequestModel().check_user_delete( - c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() + pull_request) + + if at_version: + c.allowed_to_change_status = False + else: + c.allowed_to_change_status = PullRequestModel(). \ + check_user_change_status(pull_request, c.rhodecode_user) + + if at_version: + c.allowed_to_update = False + else: + c.allowed_to_update = PullRequestModel().check_user_update( + pull_request, c.rhodecode_user) and not pull_request.is_closed() + + if at_version: + c.allowed_to_merge = False + else: + c.allowed_to_merge = PullRequestModel().check_user_merge( + pull_request, c.rhodecode_user) and not pull_request.is_closed() + + if at_version: + c.allowed_to_delete = False + else: + c.allowed_to_delete = PullRequestModel().check_user_delete( + pull_request, c.rhodecode_user) and not pull_request.is_closed() + + if at_version: + c.allowed_to_comment = False + else: + c.allowed_to_comment = not pull_request.is_closed() cc_model = ChangesetCommentsModel() - c.pull_request_reviewers = c.pull_request.reviewers_statuses() + c.pull_request_reviewers = pull_request.reviewers_statuses() - c.pull_request_review_status = c.pull_request.calculated_review_status() + c.pull_request_review_status = pull_request.calculated_review_status() c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( - c.pull_request) + pull_request) c.approval_msg = None if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: c.approval_msg = _('Reviewer approval is pending.') c.pr_merge_status = False # load compare data into template context - enable_comments = not c.pull_request.is_closed() - + enable_comments = not pull_request.is_closed() # inline comments c.inline_comments = cc_model.get_inline_comments( @@ -725,23 +813,26 @@ class PullrequestsController(BaseRepoCon c.inline_comments, version=at_version) self._load_compare_data( - c.pull_request, c.inline_comments, enable_comments=enable_comments) + pull_request, c.inline_comments, enable_comments=enable_comments) # outdated comments c.outdated_comments = {} c.outdated_cnt = 0 - if ChangesetCommentsModel.use_outdated_comments(c.pull_request): + + if ChangesetCommentsModel.use_outdated_comments(pull_request): c.outdated_comments = cc_model.get_outdated_comments( c.rhodecode_db_repo.repo_id, - pull_request=c.pull_request) + pull_request=pull_request) + # Count outdated comments and check for deleted files for file_name, lines in c.outdated_comments.iteritems(): for comments in lines.values(): + comments = [comm for comm in comments + if comm.outdated_at_version(at_version)] c.outdated_cnt += len(comments) if file_name not in c.included_files: c.deleted_files.append(file_name) - # this is a hack to properly display links, when creating PR, the # compare view and others uses different notation, and # compare_commits.html renders links based on the target_repo. @@ -760,6 +851,9 @@ class PullrequestsController(BaseRepoCon c.commit_statuses = statuses c.ancestor = None # TODO: add ancestor here + c.pull_request = pull_request_ver + c.pull_request_latest = pull_request_latest + c.at_version = at_version return render('/pullrequests/pullrequest_show.html') @@ -813,8 +907,6 @@ class PullrequestsController(BaseRepoCon closing_pr=close_pr ) - - if allowed_to_change_status: old_calculated_status = pull_request.calculated_review_status() # get status if set ! diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py --- a/rhodecode/lib/utils2.py +++ b/rhodecode/lib/utils2.py @@ -656,6 +656,16 @@ def extract_mentioned_users(s): return sorted(list(usrs), key=lambda k: k.lower()) +class UnsafeAttributeDict(dict): + def __getattr__(self, attr): + try: + return self[attr] + except KeyError: + raise AttributeError('%s object has no attribute %s' % (self, attr)) + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + + class AttributeDict(dict): def __getattr__(self, attr): return self.get(attr, None) diff --git a/rhodecode/model/__init__.py b/rhodecode/model/__init__.py --- a/rhodecode/model/__init__.py +++ b/rhodecode/model/__init__.py @@ -90,7 +90,7 @@ class BaseModel(object): """ Gets instance of given cls using some simple lookup mechanism. - :param cls: class to fetch + :param cls: classes to fetch :param instance: int or Instance :param callback: callback to call if all lookups failed """ @@ -98,6 +98,9 @@ class BaseModel(object): if isinstance(instance, cls): return instance elif isinstance(instance, (int, long)): + if isinstance(cls, tuple): + # if we pass multi instances we pick first to .get() + cls = cls[0] return cls.get(instance) else: if instance: diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py --- a/rhodecode/model/db.py +++ b/rhodecode/model/db.py @@ -2933,6 +2933,12 @@ class ChangesetComment(Base, BaseModel): def outdated(self): return self.display_state == self.COMMENT_OUTDATED + def outdated_at_version(self, version): + """ + Checks if comment is outdated for given pull request version + """ + return self.outdated and self.pull_request_version_id != version + def render(self, mentions=False): from rhodecode.lib import helpers as h return h.render(self.text, renderer=self.renderer, mentions=mentions) @@ -3117,34 +3123,6 @@ class _PullRequestBase(BaseModel): else: return None - -class PullRequest(Base, _PullRequestBase): - __tablename__ = 'pull_requests' - __table_args__ = ( - {'extend_existing': True, 'mysql_engine': 'InnoDB', - 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, - ) - - pull_request_id = Column( - 'pull_request_id', Integer(), nullable=False, primary_key=True) - - def __repr__(self): - if self.pull_request_id: - return '' % self.pull_request_id - else: - return '' % id(self) - - reviewers = relationship('PullRequestReviewers', - cascade="all, delete, delete-orphan") - statuses = relationship('ChangesetStatus') - comments = relationship('ChangesetComment', - cascade="all, delete, delete-orphan") - versions = relationship('PullRequestVersion', - cascade="all, delete, delete-orphan") - - def is_closed(self): - return self.status == self.STATUS_CLOSED - def get_api_data(self): from rhodecode.model.pull_request import PullRequestModel pull_request = self @@ -3209,6 +3187,35 @@ class PullRequest(Base, _PullRequestBase return data + +class PullRequest(Base, _PullRequestBase): + __tablename__ = 'pull_requests' + __table_args__ = ( + {'extend_existing': True, 'mysql_engine': 'InnoDB', + 'mysql_charset': 'utf8', 'sqlite_autoincrement': True}, + ) + + pull_request_id = Column( + 'pull_request_id', Integer(), nullable=False, primary_key=True) + + def __repr__(self): + if self.pull_request_id: + return '' % self.pull_request_id + else: + return '' % id(self) + + reviewers = relationship('PullRequestReviewers', + cascade="all, delete, delete-orphan") + statuses = relationship('ChangesetStatus') + comments = relationship('ChangesetComment', + cascade="all, delete, delete-orphan") + versions = relationship('PullRequestVersion', + cascade="all, delete, delete-orphan", + lazy='dynamic') + + def is_closed(self): + return self.status == self.STATUS_CLOSED + def __json__(self): return { 'revisions': self.revisions, @@ -3243,6 +3250,24 @@ class PullRequestVersion(Base, _PullRequ else: return '' % id(self) + @property + def reviewers(self): + return self.pull_request.reviewers + + @property + def versions(self): + return self.pull_request.versions + + def is_closed(self): + # calculate from original + return self.pull_request.status == self.STATUS_CLOSED + + def calculated_review_status(self): + return self.pull_request.calculated_review_status() + + def reviewers_statuses(self): + return self.pull_request.reviewers_statuses() + class PullRequestReviewers(Base, BaseModel): __tablename__ = 'pull_request_reviewers' diff --git a/rhodecode/public/css/buttons.less b/rhodecode/public/css/buttons.less --- a/rhodecode/public/css/buttons.less +++ b/rhodecode/public/css/buttons.less @@ -208,8 +208,14 @@ input[type="button"] { color: @rcdarkblue; } + //disabled buttons + //last; overrides any other styles &:disabled { + opacity: .7; + cursor: auto; + background-color: white; color: @grey4; + text-shadow: none; } // TODO: johbo: Check if we can avoid this, indicates that the structure diff --git a/rhodecode/public/css/code-block.less b/rhodecode/public/css/code-block.less --- a/rhodecode/public/css/code-block.less +++ b/rhodecode/public/css/code-block.less @@ -313,7 +313,7 @@ table.code-difftable { // Comments div.comment:target { - border-left: 6px solid @comment-highlight-color; + border-left: 6px solid @comment-highlight-color !important; padding-left: 3px; margin-left: -9px; } @@ -737,6 +737,15 @@ input.filediff-collapse-state { } } +/* Main comments*/ +#comments { + .comment-selected { + border-left: 6px solid @comment-highlight-color; + padding-left: 3px; + margin-left: -9px; + } +} + .filediff { border: 1px solid @grey5; @@ -894,6 +903,7 @@ input.filediff-collapse-state { display: none; } } + .inline-comments { border-radius: @border-radius; background: @grey6; @@ -904,6 +914,7 @@ input.filediff-collapse-state { .comment-outdated { opacity: 0.5; } + .comment-inline { background: white; padding: (@comment-padding + 3px) @comment-padding; diff --git a/rhodecode/public/css/comments.less b/rhodecode/public/css/comments.less --- a/rhodecode/public/css/comments.less +++ b/rhodecode/public/css/comments.less @@ -170,22 +170,6 @@ tr.inline-comments div { color: @rcblue; } -.outdated { - display: none; - opacity: 0.6; - - .comment { - margin: 0 0 @padding; - - .date:after { - content: none; - } - } - .outdated_comment_block { - padding: 0 0 @space 0; - } -} - // Comment Form div.comment-form { margin-top: 20px; diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less --- a/rhodecode/public/css/main.less +++ b/rhodecode/public/css/main.less @@ -1395,9 +1395,7 @@ table.integrations { width: 92%; margin-bottom: 1em; } -#update_commits { - float: right; -} + .compare_view_commits tr{ height: 20px; } 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 @@ -48,58 +48,6 @@ var tableTr = function(cls, body){ return _el.children[0].children[0].children[0]; }; -var removeInlineForm = function(form) { - form.parentNode.removeChild(form); -}; - -var createInlineForm = function(parent_tr, f_path, line) { - var tmpl = $('#comment-inline-form-template').html(); - tmpl = tmpl.format(f_path, line); - var form = tableTr('comment-form-inline', tmpl); - var form_hide_button = $(form).find('.hide-inline-form'); - - $(form_hide_button).click(function(e) { - $('.inline-comments').removeClass('hide-comment-button'); - var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode; - if ($(newtr.nextElementSibling).hasClass('inline-comments-button')) { - $(newtr.nextElementSibling).show(); - } - $(newtr).parents('.comment-form-inline').remove(); - $(parent_tr).removeClass('form-open'); - $(parent_tr).removeClass('hl-comment'); - }); - - return form; -}; - -var getLineNo = function(tr) { - var line; - // Try to get the id and return "" (empty string) if it doesn't exist - var o = ($(tr).find('.lineno.old').attr('id')||"").split('_'); - var n = ($(tr).find('.lineno.new').attr('id')||"").split('_'); - if (n.length >= 2) { - line = n[n.length-1]; - } else if (o.length >= 2) { - line = o[o.length-1]; - } - return line; -}; - -/** - * make a single inline comment and place it inside - */ -var renderInlineComment = function(json_data, show_add_button) { - show_add_button = typeof show_add_button !== 'undefined' ? show_add_button : true; - try { - var html = json_data.rendered_text; - var lineno = json_data.line_no; - var target_id = json_data.target_id; - placeInline(target_id, lineno, html, show_add_button); - } catch (e) { - console.error(e); - } -}; - function bindDeleteCommentButtons() { $('.delete-comment').one('click', function() { var comment_id = $(this).data("comment-id"); @@ -110,115 +58,6 @@ function bindDeleteCommentButtons() { }); } -/** - * Inject inline comment for on given TR this tr should be always an .line - * tr containing the line. Code will detect comment, and always put the comment - * block at the very bottom - */ -var injectInlineForm = function(tr){ - if (!$(tr).hasClass('line')) { - return; - } - - var _td = $(tr).find('.code').get(0); - if ($(tr).hasClass('form-open') || - $(tr).hasClass('context') || - $(_td).hasClass('no-comment')) { - return; - } - $(tr).addClass('form-open'); - $(tr).addClass('hl-comment'); - var node = $(tr.parentNode.parentNode.parentNode).find('.full_f_path').get(0); - var f_path = $(node).attr('path'); - var lineno = getLineNo(tr); - var form = createInlineForm(tr, f_path, lineno); - - var parent = tr; - while (1) { - var n = parent.nextElementSibling; - // next element are comments ! - if ($(n).hasClass('inline-comments')) { - parent = n; - } - else { - break; - } - } - var _parent = $(parent).get(0); - $(_parent).after(form); - $('.comment-form-inline').prev('.inline-comments').addClass('hide-comment-button'); - var f = $(form).get(0); - - var _form = $(f).find('.inline-form').get(0); - - var pullRequestId = templateContext.pull_request_data.pull_request_id; - var commitId = templateContext.commit_data.commit_id; - - var commentForm = new CommentForm(_form, commitId, pullRequestId, lineno, false); - var cm = commentForm.getCmInstance(); - - // set a CUSTOM submit handler for inline comments. - commentForm.setHandleFormSubmit(function(o) { - var text = commentForm.cm.getValue(); - - if (text === "") { - return; - } - - if (lineno === undefined) { - alert('missing line !'); - return; - } - if (f_path === undefined) { - alert('missing file path !'); - return; - } - - var excludeCancelBtn = false; - var submitEvent = true; - commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent); - commentForm.cm.setOption("readOnly", true); - var postData = { - 'text': text, - 'f_path': f_path, - 'line': lineno, - 'csrf_token': CSRF_TOKEN - }; - var submitSuccessCallback = function(o) { - $(tr).removeClass('form-open'); - removeInlineForm(f); - renderInlineComment(o); - $('.inline-comments').removeClass('hide-comment-button'); - - // re trigger the linkification of next/prev navigation - linkifyComments($('.inline-comment-injected')); - timeagoActivate(); - bindDeleteCommentButtons(); - commentForm.setActionButtonsDisabled(false); - - }; - var submitFailCallback = function(){ - commentForm.resetCommentFormState(text) - }; - commentForm.submitAjaxPOST( - commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback); - }); - - setTimeout(function() { - // callbacks - if (cm !== undefined) { - cm.focus(); - } - }, 10); - - $.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({ - form:_form, - parent:_parent, - lineno: lineno, - f_path: f_path} - ); -}; - var deleteComment = function(comment_id) { var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id); var postData = { @@ -232,89 +71,6 @@ var deleteComment = function(comment_id) ajaxPOST(url, postData, success); }; -var createInlineAddButton = function(tr){ - var label = _gettext('Add another comment'); - var html_el = document.createElement('div'); - $(html_el).addClass('add-comment'); - html_el.innerHTML = '{0}'.format(label); - var add = new $(html_el); - add.on('click', function(e) { - injectInlineForm(tr); - }); - return add; -}; - -var placeAddButton = function(target_tr){ - if(!target_tr){ - return; - } - var last_node = target_tr; - // scan - while (1){ - var n = last_node.nextElementSibling; - // next element are comments ! - if($(n).hasClass('inline-comments')){ - last_node = n; - // also remove the comment button from previous - var comment_add_buttons = $(last_node).find('.add-comment'); - for(var i=0; i - ${comment.comment_inline_form()} - ## ## render comments and inlines + ## render comments ${comment.generate_comments()} ## main comment form and it status @@ -210,12 +209,12 @@ if(button.hasClass("comments-visible")) { $('#{0} .inline-comments'.format(boxid)).each(function(index){ $(this).hide(); - }) + }); button.removeClass("comments-visible"); } else { $('#{0} .inline-comments'.format(boxid)).each(function(index){ $(this).show(); - }) + }); button.addClass("comments-visible"); } }); @@ -230,7 +229,7 @@ url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', success: function(data) { if(data.results.length === 0){ - $('#child_link').html('${_('No Child Commits')}').addClass('disabled'); + $('#child_link').html("${_('No Child Commits')}").addClass('disabled'); } if(data.results.length === 1){ var commit = data.results[0]; @@ -263,7 +262,7 @@ // >1 links show them to user to choose if(!$('#parent_link').hasClass('disabled')){ $.ajax({ - url: '${h.url('changeset_parents',repo_name=c.repo_name, revision=c.commit.raw_id)}', + url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}', success: function(data) { if(data.results.length === 0){ $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); diff --git a/rhodecode/templates/changeset/changeset_file_comment.html b/rhodecode/templates/changeset/changeset_file_comment.html --- a/rhodecode/templates/changeset/changeset_file_comment.html +++ b/rhodecode/templates/changeset/changeset_file_comment.html @@ -6,14 +6,14 @@ <%namespace name="base" file="/base/base.html"/> <%def name="comment_block(comment, inline=False)"> -
+
+
${base.gravatar_with_user(comment.author.email, 16)} @@ -22,21 +22,27 @@ ${h.age_component(comment.modified_at, time_is_local=True)}
%if comment.status_change:
@@ -52,14 +58,19 @@ ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed ## only super-admin, repo admin OR comment owner can delete %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): + ## permissions to delete %if h.HasPermissionAny('hg.admin')() or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id: ## TODO: dan: add edit comment here - ${_('Delete')} | - %if not comment.outdated: - ${_('Prev')} | - ${_('Next')} - %endif + ${_('Delete')} + %else: + %endif + %else: + + %endif + %if not comment.outdated_at_version(getattr(c, 'at_version', None)): + | ${_('Prev')} + | ${_('Next')} %endif
@@ -67,102 +78,9 @@
${comment.render(mentions=True)|n}
-
- -<%def name="comment_block_outdated(comment)"> -
-
-
-
- ${base.gravatar_with_user(comment.author.email, 16)} -
-
- ${h.age_component(comment.modified_at, time_is_local=True)} -
- %if comment.status_change: - - -
-
- ${comment.status_change[0].status_lbl} -
- %endif - - ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed - ## only super-admin, repo admin OR comment owner can delete - %if not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed()): - - %endif -
-
- ${comment.render(mentions=True)|n} -
-
- -<%def name="comment_inline_form()"> - - - - ## generate main comments <%def name="generate_comments(include_pull_request=False, is_pull_request=False)">
@@ -182,6 +100,7 @@ ## MAIN COMMENT FORM <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> + %if is_compare: <% form_id = "comments_form_compare" %> %else: diff --git a/rhodecode/templates/codeblocks/diffs.html b/rhodecode/templates/codeblocks/diffs.html --- a/rhodecode/templates/codeblocks/diffs.html +++ b/rhodecode/templates/codeblocks/diffs.html @@ -394,10 +394,13 @@ from rhodecode.lib.diffs import NEW_FILE %for comment in comments: ${commentblock.comment_block(comment, inline=True)} %endfor + + class="btn btn-secondary cb-comment-add-button ${'comment-outdated' if comments and comments[-1].outdated else ''}" + style="${'display: none;' if comments and comments[-1].outdated else ''}"> ${_('Add another comment')} +
diff --git a/rhodecode/templates/debug_style/collapsable-content.html b/rhodecode/templates/debug_style/collapsable-content.html --- a/rhodecode/templates/debug_style/collapsable-content.html +++ b/rhodecode/templates/debug_style/collapsable-content.html @@ -918,9 +918,6 @@ $(btns).each(fn_display); }); - // inject comments into they proper positions - var file_comments = $('.inline-comment-placeholder'); - renderInlineComments(file_comments); var commentTotals = {}; $.each(file_comments, function(i, comment) { var path = $(comment).attr('path'); diff --git a/rhodecode/templates/pullrequests/pullrequest_show.html b/rhodecode/templates/pullrequests/pullrequest_show.html --- a/rhodecode/templates/pullrequests/pullrequest_show.html +++ b/rhodecode/templates/pullrequests/pullrequest_show.html @@ -165,24 +165,62 @@
%if c.comments: - ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)}, + ${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)}, %else: - ${ungettext("%d Pull request comment", "%d Pull request comments", len(c.comments)) % len(c.comments)} + ${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)} %endif + %if c.inline_cnt: ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} %else: ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} %endif - - % if c.outdated_cnt: - ,${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} ${_('(Show)')} - % endif + %if c.outdated_cnt: + , ${ungettext("%d Outdated Comment", "%d Outdated Comments", c.outdated_cnt) % c.outdated_cnt} ${_('(Show)')} + %endif
-
+ + + + +
+
+
+
+ + + + + + + + % for ver in reversed(c.pull_request.versions()): + + + + + + + % endfor +
+ % if c.at_version == None: + + % endif + latest + ${c.pull_request_latest.source_ref_parts.commit_id[:6]} + ${_('created')} ${h.age_component(c.pull_request.created_on)}
+ % if c.at_version == ver.pull_request_version_id: + + % endif + version ${ver.pull_request_version_id} + ${ver.source_ref_parts.commit_id[:6]} + ${_('created')} ${h.age_component(ver.created_on)}
+
+
+