##// END OF EJS Templates
pull-requests: expose version browsing of pull requests....
pull-requests: expose version browsing of pull requests. - show nav for browsing each version of pr - show detailed changes for each of version - update comment template to indicate the changes were due to update of a pr

File last commit:

r1255:952cdf08 default
r1255:952cdf08 default
Show More
pullrequest_show.html
559 lines | 24.1 KiB | text/html | HtmlLexer
<%inherit file="/base/base.html"/>
<%def name="title()">
${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
%if c.rhodecode_name:
&middot; ${h.branding(c.rhodecode_name)}
%endif
</%def>
<%def name="breadcrumbs_links()">
<span id="pr-title">
${c.pull_request.title}
%if c.pull_request.is_closed():
(${_('Closed')})
%endif
</span>
<div id="pr-title-edit" class="input" style="display: none;">
${h.text('pullrequest_title', id_="pr-title-input", class_="large", value=c.pull_request.title)}
</div>
</%def>
<%def name="menu_bar_nav()">
${self.menu_items(active='repositories')}
</%def>
<%def name="menu_bar_subnav()">
${self.repo_menu(active='showpullrequest')}
</%def>
<%def name="main()">
<script type="text/javascript">
// TODO: marcink switch this to pyroutes
AJAX_COMMENT_DELETE_URL = "${url('pullrequest_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
</script>
<div class="box">
<div class="title">
${self.repo_page_title(c.rhodecode_db_repo)}
</div>
${self.breadcrumbs()}
<div class="box pr-summary">
<div class="summary-details block-left">
<%summary = lambda n:{False:'summary-short'}.get(n)%>
<div class="pr-details-title">
<a href="${h.url('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request #%s') % c.pull_request.pull_request_id}</a> ${_('From')} ${h.format_date(c.pull_request.created_on)}
%if c.allowed_to_update:
<div id="delete_pullrequest" class="pull-right action_button ${'' if c.allowed_to_delete else 'disabled' }" style="clear:inherit;padding: 0">
% if c.allowed_to_delete:
${h.secure_form(url('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id),method='delete')}
${h.submit('remove_%s' % c.pull_request.pull_request_id, _('Delete'),
class_="btn btn-link btn-danger",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
${h.end_form()}
% else:
${_('Delete')}
% endif
</div>
<div id="open_edit_pullrequest" class="pull-right action_button">${_('Edit')}</div>
<div id="close_edit_pullrequest" class="pull-right action_button" style="display: none;padding: 0">${_('Cancel edit')}</div>
%endif
</div>
<div id="summary" class="fields pr-details-content">
<div class="field">
<div class="label-summary">
<label>${_('Origin')}:</label>
</div>
<div class="input">
<div class="pr-origininfo">
## branch link is only valid if it is a branch
<span class="tag">
%if c.pull_request.source_ref_parts.type == 'branch':
<a href="${h.url('changelog_home', repo_name=c.pull_request.source_repo.repo_name, branch=c.pull_request.source_ref_parts.name)}">${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}</a>
%else:
${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}
%endif
</span>
<span class="clone-url">
<a href="${h.url('summary_home', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
</span>
</div>
<div class="pr-pullinfo">
%if h.is_hg(c.pull_request.source_repo):
<input type="text" value="hg pull -r ${h.short_id(c.source_ref)} ${c.pull_request.source_repo.clone_url()}" readonly="readonly">
%elif h.is_git(c.pull_request.source_repo):
<input type="text" value="git pull ${c.pull_request.source_repo.clone_url()} ${c.pull_request.source_ref_parts.name}" readonly="readonly">
%endif
</div>
</div>
</div>
<div class="field">
<div class="label-summary">
<label>${_('Target')}:</label>
</div>
<div class="input">
<div class="pr-targetinfo">
## branch link is only valid if it is a branch
<span class="tag">
%if c.pull_request.target_ref_parts.type == 'branch':
<a href="${h.url('changelog_home', repo_name=c.pull_request.target_repo.repo_name, branch=c.pull_request.target_ref_parts.name)}">${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}</a>
%else:
${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}
%endif
</span>
<span class="clone-url">
<a href="${h.url('summary_home', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
</span>
</div>
</div>
</div>
## Link to the shadow repository.
<div class="field">
<div class="label-summary">
<label>${_('Merge')}:</label>
</div>
<div class="input">
% if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
<div class="pr-mergeinfo">
%if h.is_hg(c.pull_request.target_repo):
<input type="text" value="hg clone -u ${c.pull_request.shadow_merge_ref.name} ${c.shadow_clone_url} pull-request-${c.pull_request.pull_request_id}" readonly="readonly">
%elif h.is_git(c.pull_request.target_repo):
<input type="text" value="git clone --branch ${c.pull_request.shadow_merge_ref.name} ${c.shadow_clone_url} pull-request-${c.pull_request.pull_request_id}" readonly="readonly">
%endif
</div>
% else:
<div class="">
${_('Shadow repository data not available')}.
</div>
% endif
</div>
</div>
<div class="field">
<div class="label-summary">
<label>${_('Review')}:</label>
</div>
<div class="input">
%if c.pull_request_review_status:
<div class="${'flag_status %s' % c.pull_request_review_status} tooltip pull-left"></div>
<span class="changeset-status-lbl tooltip">
%if c.pull_request.is_closed():
${_('Closed')},
%endif
${h.commit_status_lbl(c.pull_request_review_status)}
</span>
- ${ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)}
%endif
</div>
</div>
<div class="field">
<div class="pr-description-label label-summary">
<label>${_('Description')}:</label>
</div>
<div id="pr-desc" class="input">
<div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
</div>
<div id="pr-desc-edit" class="input textarea editor" style="display: none;">
<textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
</div>
</div>
<div class="field">
<div class="label-summary">
<label>${_('Comments')}:</label>
</div>
<div class="input">
<div>
<div class="comments-number">
%if c.comments:
<a href="#comments">${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)}</a>,
%else:
${ungettext("%d General Comment", "%d General Comments", len(c.comments)) % len(c.comments)}
%endif
%if c.inline_cnt:
<a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a>
%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} <span id="show-outdated-comments" class="btn btn-link">${_('(Show)')}</span>
%endif
</div>
</div>
</div>
</div>
<div class="field">
<div class="label-summary">
<label>${_('Versions')} (${len(c.versions)}):</label>
</div>
<div>
% if c.show_version_changes:
<table>
<tr>
<td>
% if c.at_version in [None, 'latest']:
<i class="icon-ok link"></i>
% endif
</td>
<td><code><a href="${h.url.current(version='latest')}">latest</a></code></td>
<td>
<code>${c.pull_request_latest.source_ref_parts.commit_id[:6]}</code>
</td>
<td>${_('created')} ${h.age_component(c.pull_request_latest.updated_on)}</td>
</tr>
% for ver in reversed(c.pull_request.versions()):
<tr>
<td>
% if c.at_version == ver.pull_request_version_id:
<i class="icon-ok link"></i>
% endif
</td>
<td><code><a href="${h.url.current(version=ver.pull_request_version_id)}">version ${ver.pull_request_version_id}</a></code></td>
<td>
<code>${ver.source_ref_parts.commit_id[:6]}</code>
</td>
<td>${_('created')} ${h.age_component(ver.updated_on)}</td>
</tr>
% endfor
</table>
% if c.at_version:
<pre>
Changed commits:
* added: ${len(c.changes.added)}
* removed: ${len(c.changes.removed)}
% if not (c.file_changes.added+c.file_changes.modified+c.file_changes.removed):
No file changes found
% else:
Changed files:
%for file_name in c.file_changes.added:
* A <a href="#${'a_' + h.FID('', file_name)}">${file_name}</a>
%endfor
%for file_name in c.file_changes.modified:
* M <a href="#${'a_' + h.FID('', file_name)}">${file_name}</a>
%endfor
%for file_name in c.file_changes.removed:
* R ${file_name}
%endfor
% endif
</pre>
% endif
% else:
${_('Pull request versions not available')}.
% endif
</div>
</div>
<div id="pr-save" class="field" style="display: none;">
<div class="label-summary"></div>
<div class="input">
<span id="edit_pull_request" class="btn btn-small">${_('Save Changes')}</span>
</div>
</div>
</div>
</div>
<div>
## AUTHOR
<div class="reviewers-title block-right">
<div class="pr-details-title">
${_('Author')}
</div>
</div>
<div class="block-right pr-details-content reviewers">
<ul class="group_members">
<li>
${self.gravatar_with_user(c.pull_request.author.email, 16)}
</li>
</ul>
</div>
## REVIEWERS
<div class="reviewers-title block-right">
<div class="pr-details-title">
${_('Pull request reviewers')}
%if c.allowed_to_update:
<span id="open_edit_reviewers" class="block-right action_button">${_('Edit')}</span>
<span id="close_edit_reviewers" class="block-right action_button" style="display: none;">${_('Close')}</span>
%endif
</div>
</div>
<div id="reviewers" class="block-right pr-details-content reviewers">
## members goes here !
<input type="hidden" name="__start__" value="review_members:sequence">
<ul id="review_members" class="group_members">
%for member,reasons,status in c.pull_request_reviewers:
<li id="reviewer_${member.user_id}">
<div class="reviewers_member">
<div class="reviewer_status tooltip" title="${h.tooltip(h.commit_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
<div class="${'flag_status %s' % (status[0][1].status if status else 'not_reviewed')} pull-left reviewer_member_status"></div>
</div>
<div id="reviewer_${member.user_id}_name" class="reviewer_name">
${self.gravatar_with_user(member.email, 16)}
</div>
<input type="hidden" name="__start__" value="reviewer:mapping">
<input type="hidden" name="__start__" value="reasons:sequence">
%for reason in reasons:
<div class="reviewer_reason">- ${reason}</div>
<input type="hidden" name="reason" value="${reason}">
%endfor
<input type="hidden" name="__end__" value="reasons:sequence">
<input id="reviewer_${member.user_id}_input" type="hidden" value="${member.user_id}" name="user_id" />
<input type="hidden" name="__end__" value="reviewer:mapping">
%if c.allowed_to_update:
<div class="reviewer_member_remove action_button" onclick="removeReviewMember(${member.user_id}, true)" style="visibility: hidden;">
<i class="icon-remove-sign" ></i>
</div>
%endif
</div>
</li>
%endfor
</ul>
<input type="hidden" name="__end__" value="review_members:sequence">
%if not c.pull_request.is_closed():
<div id="add_reviewer_input" class='ac' style="display: none;">
%if c.allowed_to_update:
<div class="reviewer_ac">
${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
<div id="reviewers_container"></div>
</div>
<div>
<span id="update_pull_request" class="btn btn-small">${_('Save Changes')}</span>
</div>
%endif
</div>
%endif
</div>
</div>
</div>
<div class="box">
##DIFF
<div class="table" >
<div id="changeset_compare_view_content">
##CS
% if c.missing_requirements:
<div class="box">
<div class="alert alert-warning">
<div>
<strong>${_('Missing requirements:')}</strong>
${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
</div>
</div>
</div>
% elif c.missing_commits:
<div class="box">
<div class="alert alert-warning">
<div>
<strong>${_('Missing commits')}:</strong>
${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
</div>
</div>
</div>
% endif
<div class="compare_view_commits_title">
% if c.allowed_to_update and not c.pull_request.is_closed():
<a id="update_commits" class="btn btn-primary pull-right">${_('Update commits')}</a>
% else:
<a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
% endif
% if len(c.commit_ranges):
<h2>${ungettext('Compare View: %s commit','Compare View: %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}</h2>
% endif
</div>
% if not c.missing_commits:
<%include file="/compare/compare_commits.html" />
<div class="cs_files">
<%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
${cbdiffs.render_diffset_menu()}
${cbdiffs.render_diffset(
c.diffset, use_comments=True,
collapse_when_files_over=30,
disable_new_comments=not c.allowed_to_comment)}
</div>
% endif
</div>
## template for inline comment form
<%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
## render general comments
${comment.generate_comments(include_pull_request=True, is_pull_request=True)}
% if not c.pull_request.is_closed():
## main comment form and it status
${comment.comments(h.url('pullrequest_comment', repo_name=c.repo_name,
pull_request_id=c.pull_request.pull_request_id),
c.pull_request_review_status,
is_pull_request=True, change_status=c.allowed_to_change_status)}
%endif
<script type="text/javascript">
if (location.hash) {
var result = splitDelimitedHash(location.hash);
var line = $('html').find(result.loc);
if (line.length > 0){
offsetScroll(line, 70);
}
}
$(function(){
ReviewerAutoComplete('user');
// custom code mirror
var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
var PRDetails = {
editButton: $('#open_edit_pullrequest'),
closeButton: $('#close_edit_pullrequest'),
deleteButton: $('#delete_pullrequest'),
viewFields: $('#pr-desc, #pr-title'),
editFields: $('#pr-desc-edit, #pr-title-edit, #pr-save'),
init: function() {
var that = this;
this.editButton.on('click', function(e) { that.edit(); });
this.closeButton.on('click', function(e) { that.view(); });
},
edit: function(event) {
this.viewFields.hide();
this.editButton.hide();
this.deleteButton.hide();
this.closeButton.show();
this.editFields.show();
codeMirrorInstance.refresh();
},
view: function(event) {
this.editButton.show();
this.deleteButton.show();
this.editFields.hide();
this.closeButton.hide();
this.viewFields.show();
}
};
var ReviewersPanel = {
editButton: $('#open_edit_reviewers'),
closeButton: $('#close_edit_reviewers'),
addButton: $('#add_reviewer_input'),
removeButtons: $('.reviewer_member_remove'),
init: function() {
var that = this;
this.editButton.on('click', function(e) { that.edit(); });
this.closeButton.on('click', function(e) { that.close(); });
},
edit: function(event) {
this.editButton.hide();
this.closeButton.show();
this.addButton.show();
this.removeButtons.css('visibility', 'visible');
},
close: function(event) {
this.editButton.show();
this.closeButton.hide();
this.addButton.hide();
this.removeButtons.css('visibility', 'hidden');
}
};
PRDetails.init();
ReviewersPanel.init();
$('#show-outdated-comments').on('click', function(e){
var button = $(this);
var outdated = $('.comment-outdated');
if (button.html() === "(Show)") {
button.html("(Hide)");
outdated.show();
} else {
button.html("(Show)");
outdated.hide();
}
});
$('.show-inline-comments').on('change', function(e){
var show = 'none';
var target = e.currentTarget;
if(target.checked){
show = ''
}
var boxid = $(target).attr('id_for');
var comments = $('#{0} .inline-comments'.format(boxid));
var fn_display = function(idx){
$(this).css('display', show);
};
$(comments).each(fn_display);
var btns = $('#{0} .inline-comments-button'.format(boxid));
$(btns).each(fn_display);
});
$('#merge_pull_request_form').submit(function() {
if (!$('#merge_pull_request').attr('disabled')) {
$('#merge_pull_request').attr('disabled', 'disabled');
}
return true;
});
$('#edit_pull_request').on('click', function(e){
var title = $('#pr-title-input').val();
var description = codeMirrorInstance.getValue();
editPullRequest(
"${c.repo_name}", "${c.pull_request.pull_request_id}",
title, description);
});
$('#update_pull_request').on('click', function(e){
updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}");
});
$('#update_commits').on('click', function(e){
var isDisabled = !$(e.currentTarget).attr('disabled');
$(e.currentTarget).text(_gettext('Updating...'));
$(e.currentTarget).attr('disabled', 'disabled');
if(isDisabled){
updateCommits("${c.repo_name}", "${c.pull_request.pull_request_id}");
}
});
// fixing issue with caches on firefox
$('#update_commits').removeAttr("disabled");
$('#close_pull_request').on('click', function(e){
closePullRequest("${c.repo_name}", "${c.pull_request.pull_request_id}");
});
$('.show-inline-comments').on('click', function(e){
var boxid = $(this).attr('data-comment-id');
var button = $(this);
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");
}
});
})
</script>
</div>
</div>
</%def>