changeset_file_comment.mako
404 lines
| 17.4 KiB
| application/x-mako
|
MakoHtmlLexer
r1282 | ## -*- coding: utf-8 -*- | ||
## usage: | |||
## <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/> | |||
## ${comment.comment_block(comment)} | |||
## | |||
<%namespace name="base" file="/base/base.mako"/> | |||
<%def name="comment_block(comment, inline=False)"> | |||
r1286 | <% pr_index_ver = comment.get_index_version(getattr(c, 'versions', [])) %> | ||
r1332 | % if inline: | ||
<% outdated_at_ver = comment.outdated_at_version(getattr(c, 'at_version_num', None)) %> | |||
% else: | |||
<% outdated_at_ver = comment.older_than_version(getattr(c, 'at_version_num', None)) %> | |||
% endif | |||
r1282 | |||
<div class="comment | |||
r1286 | ${'comment-inline' if inline else 'comment-general'} | ||
r1282 | ${'comment-outdated' if outdated_at_ver else 'comment-current'}" | ||
id="comment-${comment.comment_id}" | |||
line="${comment.line_no}" | |||
data-comment-id="${comment.comment_id}" | |||
r1325 | data-comment-type="${comment.comment_type}" | ||
data-comment-inline=${h.json.dumps(inline)} | |||
r1282 | style="${'display: none;' if outdated_at_ver else ''}"> | ||
<div class="meta"> | |||
r1325 | <div class="comment-type-label"> | ||
<div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}"> | |||
% if comment.comment_type == 'todo': | |||
% if comment.resolved: | |||
<div class="resolved tooltip" title="${_('Resolved by comment #{}').format(comment.resolved.comment_id)}"> | |||
<a href="#comment-${comment.resolved.comment_id}">${comment.comment_type}</a> | |||
</div> | |||
% else: | |||
<div class="resolved tooltip" style="display: none"> | |||
<span>${comment.comment_type}</span> | |||
</div> | |||
<div class="resolve tooltip" onclick="return Rhodecode.comments.createResolutionComment(${comment.comment_id});" title="${_('Click to resolve this comment')}"> | |||
${comment.comment_type} | |||
</div> | |||
% endif | |||
% else: | |||
% if comment.resolved_comment: | |||
fix | |||
% else: | |||
${comment.comment_type or 'note'} | |||
% endif | |||
% endif | |||
r1324 | </div> | ||
</div> | |||
r1286 | <div class="author ${'author-inline' if inline else 'author-general'}"> | ||
r1324 | ${base.gravatar_with_user(comment.author.email, 16)} | ||
r1282 | </div> | ||
<div class="date"> | |||
${h.age_component(comment.modified_at, time_is_local=True)} | |||
</div> | |||
r1286 | % if inline: | ||
<span></span> | |||
% else: | |||
r1360 | <div class="status-change"> | ||
% if comment.pull_request: | |||
r1813 | <a href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}"> | ||
r1360 | % if comment.status_change: | ||
${_('pull request #%s') % comment.pull_request.pull_request_id}: | |||
% else: | |||
${_('pull request #%s') % comment.pull_request.pull_request_id} | |||
% endif | |||
</a> | |||
% else: | |||
r1286 | % if comment.status_change: | ||
r1360 | ${_('Status change on commit')}: | ||
r1286 | % endif | ||
r1282 | % endif | ||
r1360 | </div> | ||
r1286 | % endif | ||
% if comment.status_change: | |||
r1282 | <div class="${'flag_status %s' % comment.status_change[0].status}"></div> | ||
<div title="${_('Commit status')}" class="changeset-status-lbl"> | |||
${comment.status_change[0].status_lbl} | |||
</div> | |||
r1286 | % endif | ||
r1360 | % if comment.resolved_comment: | ||
r1388 | <a class="has-spacer-before" href="#comment-${comment.resolved_comment.comment_id}" onclick="Rhodecode.comments.scrollToComment($('#comment-${comment.resolved_comment.comment_id}'), 0, ${h.json.dumps(comment.resolved_comment.outdated)})"> | ||
r1360 | ${_('resolves comment #{}').format(comment.resolved_comment.comment_id)} | ||
</a> | |||
% endif | |||
r1282 | <a class="permalink" href="#comment-${comment.comment_id}"> ¶</a> | ||
<div class="comment-links-block"> | |||
r1671 | % if comment.pull_request and comment.pull_request.author.user_id == comment.author.user_id: | ||
<span class="tag authortag tooltip" title="${_('Pull request author')}"> | |||
${_('author')} | |||
</span> | |||
| | |||
% endif | |||
r1286 | % if inline: | ||
<div class="pr-version-inline"> | |||
r1951 | <a href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}"> | ||
r1332 | % if outdated_at_ver: | ||
<code class="pr-version-num" title="${_('Outdated comment from pull request version {0}').format(pr_index_ver)}"> | |||
outdated ${'v{}'.format(pr_index_ver)} | | |||
</code> | |||
% elif pr_index_ver: | |||
<code class="pr-version-num" title="${_('Comment from pull request version {0}').format(pr_index_ver)}"> | |||
${'v{}'.format(pr_index_ver)} | | |||
</code> | |||
% endif | |||
r1286 | </a> | ||
</div> | |||
% else: | |||
% if comment.pull_request_version_id and pr_index_ver: | |||
| | |||
<div class="pr-version"> | |||
% if comment.outdated: | |||
<a href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}"> | |||
${_('Outdated comment from pull request version {}').format(pr_index_ver)} | |||
</a> | |||
% else: | |||
r1332 | <div title="${_('Comment from pull request version {0}').format(pr_index_ver)}"> | ||
r1813 | <a href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id, version=comment.pull_request_version_id)}"> | ||
r1286 | <code class="pr-version-num"> | ||
${'v{}'.format(pr_index_ver)} | |||
</code> | |||
</a> | |||
</div> | |||
% endif | |||
</div> | |||
% endif | |||
% endif | |||
r1282 | ## 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, also hide delete if currently viewed comment is outdated | |||
%if not outdated_at_ver and (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 | |||
<a onclick="return Rhodecode.comments.deleteComment(this);" class="delete-comment"> ${_('Delete')}</a> | |||
%else: | |||
<button class="btn-link" disabled="disabled"> ${_('Delete')}</button> | |||
%endif | |||
%else: | |||
<button class="btn-link" disabled="disabled"> ${_('Delete')}</button> | |||
%endif | |||
r1343 | % if outdated_at_ver: | ||
| <a onclick="return Rhodecode.comments.prevOutdatedComment(this);" class="prev-comment"> ${_('Prev')}</a> | |||
| <a onclick="return Rhodecode.comments.nextOutdatedComment(this);" class="next-comment"> ${_('Next')}</a> | |||
% else: | |||
r1282 | | <a onclick="return Rhodecode.comments.prevComment(this);" class="prev-comment"> ${_('Prev')}</a> | ||
| <a onclick="return Rhodecode.comments.nextComment(this);" class="next-comment"> ${_('Next')}</a> | |||
r1343 | % endif | ||
r1282 | |||
</div> | |||
</div> | |||
<div class="text"> | |||
r1673 | ${h.render(comment.text, renderer=comment.renderer, mentions=True)} | ||
r1282 | </div> | ||
</div> | |||
</%def> | |||
r1325 | |||
r1282 | ## generate main comments | ||
r1332 | <%def name="generate_comments(comments, include_pull_request=False, is_pull_request=False)"> | ||
r1343 | <div class="general-comments" id="comments"> | ||
r1332 | %for comment in comments: | ||
r1282 | <div id="comment-tr-${comment.comment_id}"> | ||
## only render comments that are not from pull request, or from | |||
## pull request and a status change | |||
%if not comment.pull_request or (comment.pull_request and comment.status_change) or include_pull_request: | |||
${comment_block(comment)} | |||
%endif | |||
</div> | |||
%endfor | |||
## to anchor ajax comments | |||
<div id="injected_page_comments"></div> | |||
</div> | |||
</%def> | |||
r1325 | |||
r1282 | <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> | ||
<div class="comments"> | |||
<% | |||
if is_pull_request: | |||
placeholder = _('Leave a comment on this Pull Request.') | |||
elif is_compare: | |||
r1331 | placeholder = _('Leave a comment on {} commits in this range.').format(len(form_extras)) | ||
r1282 | else: | ||
placeholder = _('Leave a comment on this Commit.') | |||
%> | |||
r1325 | |||
r1282 | % if c.rhodecode_user.username != h.DEFAULT_USER: | ||
r1326 | <div class="js-template" id="cb-comment-general-form-template"> | ||
## template generated for injection | |||
${comment_form(form_type='general', review_statuses=c.commit_statuses, form_extras=form_extras)} | |||
</div> | |||
<div id="cb-comment-general-form-placeholder" class="comment-form ac"> | |||
r1325 | ## inject form here | ||
</div> | |||
<script type="text/javascript"> | |||
var lineNo = 'general'; | |||
r1326 | var resolvesCommentId = null; | ||
r1331 | var generalCommentForm = Rhodecode.comments.createGeneralComment( | ||
lineNo, "${placeholder}", resolvesCommentId); | |||
// set custom success callback on rangeCommit | |||
% if is_compare: | |||
generalCommentForm.setHandleFormSubmit(function(o) { | |||
var self = generalCommentForm; | |||
var text = self.cm.getValue(); | |||
var status = self.getCommentStatus(); | |||
var commentType = self.getCommentType(); | |||
if (text === "" && !status) { | |||
return; | |||
} | |||
// we can pick which commits we want to make the comment by | |||
// selecting them via click on preview pane, this will alter the hidden inputs | |||
var cherryPicked = $('#changeset_compare_view_content .compare_select.hl').length > 0; | |||
var commitIds = []; | |||
$('#changeset_compare_view_content .compare_select').each(function(el) { | |||
var commitId = this.id.replace('row-', ''); | |||
if ($(this).hasClass('hl') || !cherryPicked) { | |||
$("input[data-commit-id='{0}']".format(commitId)).val(commitId); | |||
commitIds.push(commitId); | |||
} else { | |||
$("input[data-commit-id='{0}']".format(commitId)).val('') | |||
} | |||
}); | |||
self.setActionButtonsDisabled(true); | |||
self.cm.setOption("readOnly", true); | |||
var postData = { | |||
'text': text, | |||
'changeset_status': status, | |||
'comment_type': commentType, | |||
'commit_ids': commitIds, | |||
'csrf_token': CSRF_TOKEN | |||
}; | |||
var submitSuccessCallback = function(o) { | |||
location.reload(true); | |||
}; | |||
var submitFailCallback = function(){ | |||
self.resetCommentFormState(text) | |||
}; | |||
self.submitAjaxPOST( | |||
self.submitUrl, postData, submitSuccessCallback, submitFailCallback); | |||
}); | |||
% endif | |||
r1325 | </script> | ||
r1282 | % else: | ||
r1325 | ## form state when not logged in | ||
r1282 | <div class="comment-form ac"> | ||
<div class="comment-area"> | |||
<div class="comment-area-header"> | |||
<ul class="nav-links clearfix"> | |||
<li class="active"> | |||
<a class="disabled" href="#edit-btn" disabled="disabled" onclick="return false">${_('Write')}</a> | |||
</li> | |||
<li class=""> | |||
<a class="disabled" href="#preview-btn" disabled="disabled" onclick="return false">${_('Preview')}</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<div class="comment-area-write" style="display: block;"> | |||
<div id="edit-container"> | |||
<div style="padding: 40px 0"> | |||
${_('You need to be logged in to leave comments.')} | |||
<a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a> | |||
</div> | |||
</div> | |||
<div id="preview-container" class="clearfix" style="display: none;"> | |||
<div id="preview-box" class="preview-box"></div> | |||
</div> | |||
</div> | |||
<div class="comment-area-footer"> | |||
<div class="toolbar"> | |||
<div class="toolbar-text"> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="comment-footer"> | |||
</div> | |||
</div> | |||
% endif | |||
r1325 | <script type="text/javascript"> | ||
bindToggleButtons(); | |||
</script> | |||
r1282 | </div> | ||
r1325 | </%def> | ||
<%def name="comment_form(form_type, form_id='', lineno_id='{1}', review_statuses=None, form_extras=None)"> | |||
## comment injected based on assumption that user is logged in | |||
<form ${'id="{}"'.format(form_id) if form_id else '' |n} action="#" method="GET"> | |||
r1282 | |||
r1325 | <div class="comment-area"> | ||
<div class="comment-area-header"> | |||
<ul class="nav-links clearfix"> | |||
<li class="active"> | |||
<a href="#edit-btn" tabindex="-1" id="edit-btn_${lineno_id}">${_('Write')}</a> | |||
</li> | |||
<li class=""> | |||
<a href="#preview-btn" tabindex="-1" id="preview-btn_${lineno_id}">${_('Preview')}</a> | |||
</li> | |||
<li class="pull-right"> | |||
<select class="comment-type" id="comment_type_${lineno_id}" name="comment_type"> | |||
% for val in c.visual.comment_types: | |||
<option value="${val}">${val.upper()}</option> | |||
% endfor | |||
</select> | |||
</li> | |||
</ul> | |||
</div> | |||
<div class="comment-area-write" style="display: block;"> | |||
<div id="edit-container_${lineno_id}"> | |||
<textarea id="text_${lineno_id}" name="text" class="comment-block-ta ac-input"></textarea> | |||
</div> | |||
<div id="preview-container_${lineno_id}" class="clearfix" style="display: none;"> | |||
<div id="preview-box_${lineno_id}" class="preview-box"></div> | |||
</div> | |||
</div> | |||
r1282 | |||
r1325 | <div class="comment-area-footer"> | ||
<div class="toolbar"> | |||
<div class="toolbar-text"> | |||
r1381 | ${(_('Comments parsed using %s syntax with %s, and %s actions support.') % ( | ||
r1679 | ('<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())), | ||
r1381 | ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user')), | ||
('<span class="tooltip" title="%s">`/`</span>' % _('Start typing with / for certain actions to be triggered via text box.')) | |||
r1325 | ) | ||
)|n} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="comment-footer"> | |||
r1282 | |||
r1325 | % if review_statuses: | ||
<div class="status_box"> | |||
r1326 | <select id="change_status_${lineno_id}" name="changeset_status"> | ||
r1325 | <option></option> ## Placeholder | ||
% for status, lbl in review_statuses: | |||
<option value="${status}" data-status="${status}">${lbl}</option> | |||
%if is_pull_request and change_status and status in ('approved', 'rejected'): | |||
<option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option> | |||
%endif | |||
% endfor | |||
</select> | |||
</div> | |||
% endif | |||
r1282 | |||
r1325 | ## inject extra inputs into the form | ||
% if form_extras and isinstance(form_extras, (list, tuple)): | |||
<div id="comment_form_extras"> | |||
% for form_ex_el in form_extras: | |||
${form_ex_el|n} | |||
% endfor | |||
</div> | |||
% endif | |||
<div class="action-buttons"> | |||
## inline for has a file, and line-number together with cancel hide button. | |||
% if form_type == 'inline': | |||
<input type="hidden" name="f_path" value="{0}"> | |||
<input type="hidden" name="line" value="${lineno_id}"> | |||
<button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> | |||
${_('Cancel')} | |||
</button> | |||
% endif | |||
r1445 | |||
% if form_type != 'inline': | |||
<div class="action-buttons-extra"></div> | |||
% endif | |||
r1325 | ${h.submit('save', _('Comment'), class_='btn btn-success comment-button-input')} | ||
</div> | |||
</div> | |||
</form> | |||
</%def> |