comments: multiple changes on comments navigation/display logic
- toggle are smarter, they open/hide windows accorind to actions. E.g commenting opens threads - toggle are mor explicit - possible to hide/show only single threads - when channelstream is enabled comments are now live-pushed to diff with NEW marker indicator - new UI for showing thread comments
This commit is contained in:
parent
dc29bb13b7
commit
1ebb2411e9
20 changed files with 718 additions and 412 deletions
|
|
@ -252,7 +252,7 @@ But please check this code
|
|||
var comment = $('#comment-'+commentId);
|
||||
var commentData = comment.data();
|
||||
if (commentData.commentInline) {
|
||||
this.createComment(comment, commentId)
|
||||
this.createComment(comment, f_path, line_no, commentId)
|
||||
} else {
|
||||
Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -383,6 +383,9 @@ class RepoCommitsView(RepoAppView):
|
|||
text = self.request.POST.get('text')
|
||||
comment_type = self.request.POST.get('comment_type')
|
||||
resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
|
||||
f_path = self.request.POST.get('f_path')
|
||||
line_no = self.request.POST.get('line')
|
||||
target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path)))
|
||||
|
||||
if status:
|
||||
text = text or (_('Status change %(transition_icon)s %(status)s')
|
||||
|
|
@ -404,8 +407,8 @@ class RepoCommitsView(RepoAppView):
|
|||
repo=self.db_repo.repo_id,
|
||||
user=self._rhodecode_db_user.user_id,
|
||||
commit_id=current_id,
|
||||
f_path=self.request.POST.get('f_path'),
|
||||
line_no=self.request.POST.get('line'),
|
||||
f_path=f_path,
|
||||
line_no=line_no,
|
||||
status_change=(ChangesetStatus.get_status_lbl(status)
|
||||
if status else None),
|
||||
status_change_type=status,
|
||||
|
|
@ -447,19 +450,20 @@ class RepoCommitsView(RepoAppView):
|
|||
# finalize, commit and redirect
|
||||
Session().commit()
|
||||
|
||||
data = {
|
||||
'target_id': h.safeid(h.safe_unicode(
|
||||
self.request.POST.get('f_path'))),
|
||||
}
|
||||
data = {}
|
||||
if comment:
|
||||
comment_id = comment.comment_id
|
||||
data[comment_id] = {
|
||||
'target_id': target_elem_id
|
||||
}
|
||||
c.co = comment
|
||||
c.at_version_num = 0
|
||||
rendered_comment = render(
|
||||
'rhodecode:templates/changeset/changeset_comment_block.mako',
|
||||
self._get_template_context(c), self.request)
|
||||
|
||||
data.update(comment.get_dict())
|
||||
data.update({'rendered_text': rendered_comment})
|
||||
data[comment_id].update(comment.get_dict())
|
||||
data[comment_id].update({'rendered_text': rendered_comment})
|
||||
|
||||
comment_broadcast_channel = channelstream.comment_channel(
|
||||
self.db_repo_name, commit_obj=commit)
|
||||
|
|
|
|||
|
|
@ -983,8 +983,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
}
|
||||
return data
|
||||
|
||||
def _get_existing_ids(self, post_data):
|
||||
return filter(lambda e: e, map(safe_int, aslist(post_data.get('comments'), ',')))
|
||||
@classmethod
|
||||
def get_comment_ids(cls, post_data):
|
||||
return filter(lambda e: e > 0, map(safe_int, aslist(post_data.get('comments'), ',')))
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
|
|
@ -1022,7 +1023,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
self.register_comments_vars(c, pull_request_latest, versions, include_drafts=False)
|
||||
all_comments = c.inline_comments_flat + c.comments
|
||||
|
||||
existing_ids = self._get_existing_ids(self.request.POST)
|
||||
existing_ids = self.get_comment_ids(self.request.POST)
|
||||
return _render('comments_table', all_comments, len(all_comments),
|
||||
existing_ids=existing_ids)
|
||||
|
||||
|
|
@ -1064,7 +1065,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
.get_pull_request_resolved_todos(pull_request, include_drafts=False)
|
||||
|
||||
all_comments = c.unresolved_comments + c.resolved_comments
|
||||
existing_ids = self._get_existing_ids(self.request.POST)
|
||||
existing_ids = self.get_comment_ids(self.request.POST)
|
||||
return _render('comments_table', all_comments, len(c.unresolved_comments),
|
||||
todo_comments=True, existing_ids=existing_ids)
|
||||
|
||||
|
|
@ -1518,6 +1519,150 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
self._rhodecode_user)
|
||||
raise HTTPNotFound()
|
||||
|
||||
def _pull_request_comments_create(self, pull_request, comments):
|
||||
_ = self.request.translate
|
||||
data = {}
|
||||
pull_request_id = pull_request.pull_request_id
|
||||
if not comments:
|
||||
return
|
||||
|
||||
all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments)
|
||||
|
||||
for entry in comments:
|
||||
c = self.load_default_context()
|
||||
comment_type = entry['comment_type']
|
||||
text = entry['text']
|
||||
status = entry['status']
|
||||
is_draft = str2bool(entry['is_draft'])
|
||||
resolves_comment_id = entry['resolves_comment_id']
|
||||
close_pull_request = entry['close_pull_request']
|
||||
f_path = entry['f_path']
|
||||
line_no = entry['line']
|
||||
target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path)))
|
||||
|
||||
# the logic here should work like following, if we submit close
|
||||
# pr comment, use `close_pull_request_with_comment` function
|
||||
# else handle regular comment logic
|
||||
|
||||
if close_pull_request:
|
||||
# only owner or admin or person with write permissions
|
||||
allowed_to_close = PullRequestModel().check_user_update(
|
||||
pull_request, self._rhodecode_user)
|
||||
if not allowed_to_close:
|
||||
log.debug('comment: forbidden because not allowed to close '
|
||||
'pull request %s', pull_request_id)
|
||||
raise HTTPForbidden()
|
||||
|
||||
# This also triggers `review_status_change`
|
||||
comment, status = PullRequestModel().close_pull_request_with_comment(
|
||||
pull_request, self._rhodecode_user, self.db_repo, message=text,
|
||||
auth_user=self._rhodecode_user)
|
||||
Session().flush()
|
||||
is_inline = comment.is_inline
|
||||
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'comment',
|
||||
data={'comment': comment})
|
||||
|
||||
else:
|
||||
# regular comment case, could be inline, or one with status.
|
||||
# for that one we check also permissions
|
||||
# Additionally ENSURE if somehow draft is sent we're then unable to change status
|
||||
allowed_to_change_status = PullRequestModel().check_user_change_status(
|
||||
pull_request, self._rhodecode_user) and not is_draft
|
||||
|
||||
if status and allowed_to_change_status:
|
||||
message = (_('Status change %(transition_icon)s %(status)s')
|
||||
% {'transition_icon': '>',
|
||||
'status': ChangesetStatus.get_status_lbl(status)})
|
||||
text = text or message
|
||||
|
||||
comment = CommentsModel().create(
|
||||
text=text,
|
||||
repo=self.db_repo.repo_id,
|
||||
user=self._rhodecode_user.user_id,
|
||||
pull_request=pull_request,
|
||||
f_path=f_path,
|
||||
line_no=line_no,
|
||||
status_change=(ChangesetStatus.get_status_lbl(status)
|
||||
if status and allowed_to_change_status else None),
|
||||
status_change_type=(status
|
||||
if status and allowed_to_change_status else None),
|
||||
comment_type=comment_type,
|
||||
is_draft=is_draft,
|
||||
resolves_comment_id=resolves_comment_id,
|
||||
auth_user=self._rhodecode_user,
|
||||
send_email=not is_draft, # skip notification for draft comments
|
||||
)
|
||||
is_inline = comment.is_inline
|
||||
|
||||
if allowed_to_change_status:
|
||||
# calculate old status before we change it
|
||||
old_calculated_status = pull_request.calculated_review_status()
|
||||
|
||||
# get status if set !
|
||||
if status:
|
||||
ChangesetStatusModel().set_status(
|
||||
self.db_repo.repo_id,
|
||||
status,
|
||||
self._rhodecode_user.user_id,
|
||||
comment,
|
||||
pull_request=pull_request
|
||||
)
|
||||
|
||||
Session().flush()
|
||||
# this is somehow required to get access to some relationship
|
||||
# loaded on comment
|
||||
Session().refresh(comment)
|
||||
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'comment',
|
||||
data={'comment': comment})
|
||||
|
||||
# we now calculate the status of pull request, and based on that
|
||||
# calculation we set the commits status
|
||||
calculated_status = pull_request.calculated_review_status()
|
||||
if old_calculated_status != calculated_status:
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'review_status_change',
|
||||
data={'status': calculated_status})
|
||||
|
||||
comment_id = comment.comment_id
|
||||
data[comment_id] = {
|
||||
'target_id': target_elem_id
|
||||
}
|
||||
Session().flush()
|
||||
|
||||
c.co = comment
|
||||
c.at_version_num = None
|
||||
c.is_new = True
|
||||
rendered_comment = render(
|
||||
'rhodecode:templates/changeset/changeset_comment_block.mako',
|
||||
self._get_template_context(c), self.request)
|
||||
|
||||
data[comment_id].update(comment.get_dict())
|
||||
data[comment_id].update({'rendered_text': rendered_comment})
|
||||
|
||||
Session().commit()
|
||||
|
||||
# skip channelstream for draft comments
|
||||
if all_drafts:
|
||||
comment_broadcast_channel = channelstream.comment_channel(
|
||||
self.db_repo_name, pull_request_obj=pull_request)
|
||||
|
||||
comment_data = data
|
||||
comment_type = 'inline' if is_inline else 'general'
|
||||
if len(data) == 1:
|
||||
msg = _('posted {} new {} comment').format(len(data), comment_type)
|
||||
else:
|
||||
msg = _('posted {} new {} comments').format(len(data), comment_type)
|
||||
|
||||
channelstream.comment_channelstream_push(
|
||||
self.request, comment_broadcast_channel, self._rhodecode_user, msg,
|
||||
comment_data=comment_data)
|
||||
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
|
|
@ -1529,9 +1674,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
def pull_request_comment_create(self):
|
||||
_ = self.request.translate
|
||||
|
||||
pull_request = PullRequest.get_or_404(
|
||||
self.request.matchdict['pull_request_id'])
|
||||
pull_request_id = pull_request.pull_request_id
|
||||
pull_request = PullRequest.get_or_404(self.request.matchdict['pull_request_id'])
|
||||
|
||||
if pull_request.is_closed():
|
||||
log.debug('comment: forbidden because pull request is closed')
|
||||
|
|
@ -1543,130 +1686,17 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
log.debug('comment: forbidden because pull request is from forbidden repo')
|
||||
raise HTTPForbidden()
|
||||
|
||||
c = self.load_default_context()
|
||||
|
||||
status = self.request.POST.get('changeset_status', None)
|
||||
text = self.request.POST.get('text')
|
||||
comment_type = self.request.POST.get('comment_type')
|
||||
is_draft = str2bool(self.request.POST.get('draft'))
|
||||
resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
|
||||
close_pull_request = self.request.POST.get('close_pull_request')
|
||||
|
||||
# the logic here should work like following, if we submit close
|
||||
# pr comment, use `close_pull_request_with_comment` function
|
||||
# else handle regular comment logic
|
||||
|
||||
if close_pull_request:
|
||||
# only owner or admin or person with write permissions
|
||||
allowed_to_close = PullRequestModel().check_user_update(
|
||||
pull_request, self._rhodecode_user)
|
||||
if not allowed_to_close:
|
||||
log.debug('comment: forbidden because not allowed to close '
|
||||
'pull request %s', pull_request_id)
|
||||
raise HTTPForbidden()
|
||||
|
||||
# This also triggers `review_status_change`
|
||||
comment, status = PullRequestModel().close_pull_request_with_comment(
|
||||
pull_request, self._rhodecode_user, self.db_repo, message=text,
|
||||
auth_user=self._rhodecode_user)
|
||||
Session().flush()
|
||||
is_inline = comment.is_inline
|
||||
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'comment',
|
||||
data={'comment': comment})
|
||||
|
||||
else:
|
||||
# regular comment case, could be inline, or one with status.
|
||||
# for that one we check also permissions
|
||||
# Additionally ENSURE if somehow draft is sent we're then unable to change status
|
||||
allowed_to_change_status = PullRequestModel().check_user_change_status(
|
||||
pull_request, self._rhodecode_user) and not is_draft
|
||||
|
||||
if status and allowed_to_change_status:
|
||||
message = (_('Status change %(transition_icon)s %(status)s')
|
||||
% {'transition_icon': '>',
|
||||
'status': ChangesetStatus.get_status_lbl(status)})
|
||||
text = text or message
|
||||
|
||||
comment = CommentsModel().create(
|
||||
text=text,
|
||||
repo=self.db_repo.repo_id,
|
||||
user=self._rhodecode_user.user_id,
|
||||
pull_request=pull_request,
|
||||
f_path=self.request.POST.get('f_path'),
|
||||
line_no=self.request.POST.get('line'),
|
||||
status_change=(ChangesetStatus.get_status_lbl(status)
|
||||
if status and allowed_to_change_status else None),
|
||||
status_change_type=(status
|
||||
if status and allowed_to_change_status else None),
|
||||
comment_type=comment_type,
|
||||
is_draft=is_draft,
|
||||
resolves_comment_id=resolves_comment_id,
|
||||
auth_user=self._rhodecode_user,
|
||||
send_email=not is_draft, # skip notification for draft comments
|
||||
)
|
||||
is_inline = comment.is_inline
|
||||
|
||||
if allowed_to_change_status:
|
||||
# calculate old status before we change it
|
||||
old_calculated_status = pull_request.calculated_review_status()
|
||||
|
||||
# get status if set !
|
||||
if status:
|
||||
ChangesetStatusModel().set_status(
|
||||
self.db_repo.repo_id,
|
||||
status,
|
||||
self._rhodecode_user.user_id,
|
||||
comment,
|
||||
pull_request=pull_request
|
||||
)
|
||||
|
||||
Session().flush()
|
||||
# this is somehow required to get access to some relationship
|
||||
# loaded on comment
|
||||
Session().refresh(comment)
|
||||
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'comment',
|
||||
data={'comment': comment})
|
||||
|
||||
# we now calculate the status of pull request, and based on that
|
||||
# calculation we set the commits status
|
||||
calculated_status = pull_request.calculated_review_status()
|
||||
if old_calculated_status != calculated_status:
|
||||
PullRequestModel().trigger_pull_request_hook(
|
||||
pull_request, self._rhodecode_user, 'review_status_change',
|
||||
data={'status': calculated_status})
|
||||
|
||||
Session().commit()
|
||||
|
||||
data = {
|
||||
'target_id': h.safeid(h.safe_unicode(
|
||||
self.request.POST.get('f_path'))),
|
||||
comment_data = {
|
||||
'comment_type': self.request.POST.get('comment_type'),
|
||||
'text': self.request.POST.get('text'),
|
||||
'status': self.request.POST.get('changeset_status', None),
|
||||
'is_draft': self.request.POST.get('draft'),
|
||||
'resolves_comment_id': self.request.POST.get('resolves_comment_id', None),
|
||||
'close_pull_request': self.request.POST.get('close_pull_request'),
|
||||
'f_path': self.request.POST.get('f_path'),
|
||||
'line': self.request.POST.get('line'),
|
||||
}
|
||||
|
||||
if comment:
|
||||
c.co = comment
|
||||
c.at_version_num = None
|
||||
rendered_comment = render(
|
||||
'rhodecode:templates/changeset/changeset_comment_block.mako',
|
||||
self._get_template_context(c), self.request)
|
||||
|
||||
data.update(comment.get_dict())
|
||||
data.update({'rendered_text': rendered_comment})
|
||||
|
||||
# skip channelstream for draft comments
|
||||
if not is_draft:
|
||||
comment_broadcast_channel = channelstream.comment_channel(
|
||||
self.db_repo_name, pull_request_obj=pull_request)
|
||||
|
||||
comment_data = data
|
||||
comment_type = 'inline' if is_inline else 'general'
|
||||
channelstream.comment_channelstream_push(
|
||||
self.request, comment_broadcast_channel, self._rhodecode_user,
|
||||
_('posted a new {} comment').format(comment_type),
|
||||
comment_data=comment_data)
|
||||
data = self._pull_request_comments_create(pull_request, [comment_data])
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -339,13 +339,12 @@ def comment_channelstream_push(request, comment_broadcast_channel, user, msg, **
|
|||
|
||||
comment_data = kwargs.pop('comment_data', {})
|
||||
user_data = kwargs.pop('user_data', {})
|
||||
comment_id = comment_data.get('comment_id')
|
||||
comment_id = comment_data.keys()[0] if comment_data else ''
|
||||
|
||||
message = '<strong>{}</strong> {} #{}, {}'.format(
|
||||
message = '<strong>{}</strong> {} #{}'.format(
|
||||
user.username,
|
||||
msg,
|
||||
comment_id,
|
||||
_reload_link(_('Reload page to see new comments')),
|
||||
)
|
||||
|
||||
message_obj = {
|
||||
|
|
|
|||
|
|
@ -1148,7 +1148,7 @@ class DiffLimitExceeded(Exception):
|
|||
|
||||
# NOTE(marcink): if diffs.mako change, probably this
|
||||
# needs a bump to next version
|
||||
CURRENT_DIFF_VERSION = 'v4'
|
||||
CURRENT_DIFF_VERSION = 'v5'
|
||||
|
||||
|
||||
def _cleanup_cache_file(cached_diff_file):
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ input[type="button"] {
|
|||
color: @alert2;
|
||||
|
||||
&:hover {
|
||||
color: darken(@alert2,30%);
|
||||
color: darken(@alert2, 30%);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
|
|
|
|||
|
|
@ -1002,7 +1002,7 @@ input.filediff-collapse-state {
|
|||
.nav-chunk {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
margin-top: -17px;
|
||||
margin-top: -15px;
|
||||
}
|
||||
|
||||
.nav-chunk.selected {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
|
||||
// Comments
|
||||
@comment-outdated-opacity: 0.6;
|
||||
@comment-outdated-opacity: 1.0;
|
||||
|
||||
.comments {
|
||||
width: 100%;
|
||||
|
|
@ -64,32 +64,34 @@ tr.inline-comments div {
|
|||
.comment-draft {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
font-weight: 600;
|
||||
color: @alert3;
|
||||
font-weight: 400;
|
||||
color: @color-draft;
|
||||
}
|
||||
|
||||
.comment-new {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
font-weight: 400;
|
||||
color: @color-new;
|
||||
}
|
||||
|
||||
.comment-label {
|
||||
float: left;
|
||||
|
||||
padding: 0.4em 0.4em;
|
||||
margin: 2px 4px 0px 0px;
|
||||
display: inline-block;
|
||||
padding: 0 8px 0 0;
|
||||
min-height: 0;
|
||||
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
line-height: .8em;
|
||||
|
||||
font-family: @text-italic;
|
||||
font-style: italic;
|
||||
background: #fff none;
|
||||
color: @grey3;
|
||||
border: 1px solid @grey4;
|
||||
white-space: nowrap;
|
||||
|
||||
text-transform: uppercase;
|
||||
min-width: 50px;
|
||||
border-radius: 4px;
|
||||
|
||||
&.todo {
|
||||
color: @color5;
|
||||
|
|
@ -277,63 +279,164 @@ tr.inline-comments div {
|
|||
.comment-outdated {
|
||||
opacity: @comment-outdated-opacity;
|
||||
}
|
||||
|
||||
.comment-outdated-label {
|
||||
color: @grey3;
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-comments {
|
||||
border-radius: @border-radius;
|
||||
|
||||
.comment {
|
||||
margin: 0;
|
||||
border-radius: @border-radius;
|
||||
}
|
||||
|
||||
.comment-outdated {
|
||||
opacity: @comment-outdated-opacity;
|
||||
}
|
||||
|
||||
.comment-outdated-label {
|
||||
color: @grey3;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.comment-inline {
|
||||
|
||||
&:first-child {
|
||||
margin: 4px 4px 0 4px;
|
||||
border-top: 1px solid @grey5;
|
||||
border-bottom: 0 solid @grey5;
|
||||
border-left: 1px solid @grey5;
|
||||
border-right: 1px solid @grey5;
|
||||
.border-radius-top(4px);
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
margin: 4px 4px 0 4px;
|
||||
border-top: 1px solid @grey5;
|
||||
border-bottom: 0 solid @grey5;
|
||||
border-left: 1px solid @grey5;
|
||||
border-right: 1px solid @grey5;
|
||||
.border-radius-top(4px);
|
||||
}
|
||||
|
||||
background: white;
|
||||
padding: @comment-padding @comment-padding;
|
||||
border: @comment-padding solid @grey6;
|
||||
margin: 0 4px 0 4px;
|
||||
border-top: 0 solid @grey5;
|
||||
border-bottom: 0 solid @grey5;
|
||||
border-left: 1px solid @grey5;
|
||||
border-right: 1px solid @grey5;
|
||||
|
||||
.text {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.meta {
|
||||
border-bottom: 1px solid @grey6;
|
||||
margin: -5px 0px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
}
|
||||
.comment-selected {
|
||||
border-left: 6px solid @comment-highlight-color;
|
||||
}
|
||||
|
||||
.comment-inline-form-open {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.comment-inline-form {
|
||||
padding: @comment-padding;
|
||||
display: none;
|
||||
}
|
||||
.cb-comment-add-button {
|
||||
margin: @comment-padding;
|
||||
|
||||
.comment-inline-form-edit {
|
||||
padding: 0;
|
||||
margin: 0px 4px 2px 4px;
|
||||
}
|
||||
/* hide add comment button when form is open */
|
||||
|
||||
.reply-thread-container {
|
||||
display: table;
|
||||
width: 100%;
|
||||
padding: 0px 4px 4px 4px;
|
||||
}
|
||||
|
||||
.reply-thread-container-wrapper {
|
||||
margin: 0 4px 4px 4px;
|
||||
border-top: 0 solid @grey5;
|
||||
border-bottom: 1px solid @grey5;
|
||||
border-left: 1px solid @grey5;
|
||||
border-right: 1px solid @grey5;
|
||||
.border-radius-bottom(4px);
|
||||
}
|
||||
|
||||
.reply-thread-gravatar {
|
||||
display: table-cell;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding-top: 10px;
|
||||
padding-left: 10px;
|
||||
background-color: #eeeeee;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.reply-thread-reply-button {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
height: 33px;
|
||||
padding: 3px 8px;
|
||||
margin-left: 8px;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.reply-thread-reply-button .cb-comment-add-button {
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
padding: 6px 2px;
|
||||
text-align: left;
|
||||
cursor: text;
|
||||
color: @grey3;
|
||||
}
|
||||
.reply-thread-reply-button .cb-comment-add-button:hover {
|
||||
background-color: white;
|
||||
color: @grey2;
|
||||
}
|
||||
|
||||
.reply-thread-last {
|
||||
display: table-cell;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
/* Hide reply box when it's a first element,
|
||||
can happen when drafts are saved but not shown to specific user,
|
||||
or there are outdated comments hidden
|
||||
*/
|
||||
.reply-thread-container-wrapper:first-child:not(.comment-form-active) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.reply-thread-container-wrapper.comment-outdated {
|
||||
display: none
|
||||
}
|
||||
|
||||
/* hide add comment button when form is open */
|
||||
.comment-inline-form-open ~ .cb-comment-add-button {
|
||||
display: none;
|
||||
}
|
||||
.comment-inline-form-open {
|
||||
display: block;
|
||||
}
|
||||
/* hide add comment button when form but no comments */
|
||||
.comment-inline-form:first-child + .cb-comment-add-button {
|
||||
display: none;
|
||||
}
|
||||
/* hide add comment button when no comments or form */
|
||||
.cb-comment-add-button:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* hide add comment button when only comment is being deleted */
|
||||
.comment-deleting:first-child + .cb-comment-add-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* hide add comment button when form but no comments */
|
||||
.comment-inline-form:first-child + .cb-comment-add-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.show-outdated-comments {
|
||||
display: inline;
|
||||
|
|
@ -387,23 +490,40 @@ form.comment-form {
|
|||
}
|
||||
|
||||
.comment-footer {
|
||||
position: relative;
|
||||
display: table;
|
||||
width: 100%;
|
||||
min-height: 42px;
|
||||
height: 42px;
|
||||
|
||||
.status_box,
|
||||
.comment-status-box,
|
||||
.cancel-button {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.status_box {
|
||||
.comment-status-box {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
display: table-cell;
|
||||
padding: 5px 0 5px 2px;
|
||||
}
|
||||
|
||||
.toolbar-text {
|
||||
height: 42px;
|
||||
display: table-cell;
|
||||
vertical-align: bottom;
|
||||
font-size: 11px;
|
||||
color: @grey4;
|
||||
text-align: right;
|
||||
|
||||
a {
|
||||
color: @grey4;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons-extra {
|
||||
|
|
@ -434,10 +554,6 @@ form.comment-form {
|
|||
margin-right: 0;
|
||||
}
|
||||
|
||||
.comment-footer {
|
||||
margin-bottom: 50px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -489,8 +605,8 @@ form.comment-form {
|
|||
.injected_diff .comment-inline-form,
|
||||
.comment-inline-form {
|
||||
background-color: white;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.inline-form {
|
||||
|
|
@ -526,9 +642,6 @@ form.comment-form {
|
|||
margin: 0px;
|
||||
}
|
||||
|
||||
.comment-inline-form .comment-footer {
|
||||
margin: 10px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.hide-inline-form-button {
|
||||
margin-left: 5px;
|
||||
|
|
@ -554,6 +667,7 @@ comment-area-text {
|
|||
|
||||
.comment-area-header {
|
||||
height: 35px;
|
||||
border-bottom: 1px solid @grey5;
|
||||
}
|
||||
|
||||
.comment-area-header .nav-links {
|
||||
|
|
@ -561,6 +675,7 @@ comment-area-text {
|
|||
flex-flow: row wrap;
|
||||
-webkit-flex-flow: row wrap;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.comment-area-footer {
|
||||
|
|
@ -629,14 +744,3 @@ comment-area-text {
|
|||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.toolbar-text {
|
||||
float: right;
|
||||
font-size: 11px;
|
||||
color: @grey4;
|
||||
text-align: right;
|
||||
|
||||
a {
|
||||
color: @grey4;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3212,8 +3212,13 @@ details:not([open]) > :not(summary) {
|
|||
|
||||
.sidebar-element {
|
||||
margin-top: 20px;
|
||||
|
||||
.icon-draft {
|
||||
color: @color-draft
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.right-sidebar-collapsed-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -3235,5 +3240,4 @@ details:not([open]) > :not(summary) {
|
|||
|
||||
.old-comments-marker td {
|
||||
padding-top: 15px;
|
||||
border-bottom: 1px solid @grey5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
// Highlight color for lines and colors
|
||||
@comment-highlight-color: #ffd887;
|
||||
@color-draft: darken(@alert3, 30%);
|
||||
@color-new: darken(@alert1, 5%);
|
||||
|
||||
// FONTS
|
||||
@basefontsize: 13px;
|
||||
|
|
|
|||
|
|
@ -71,14 +71,20 @@ export class RhodecodeApp extends PolymerElement {
|
|||
if (elem) {
|
||||
elem.handleNotification(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleComment(data) {
|
||||
if (data.message.comment_id) {
|
||||
|
||||
if (data.message.comment_data.length !== 0) {
|
||||
if (window.refreshAllComments !== undefined) {
|
||||
refreshAllComments()
|
||||
}
|
||||
var json_data = data.message.comment_data;
|
||||
|
||||
if (window.commentsController !== undefined) {
|
||||
|
||||
window.commentsController.attachComment(json_data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,12 +364,15 @@ var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
|
|||
postData['close_pull_request'] = true;
|
||||
}
|
||||
|
||||
var submitSuccessCallback = function(o) {
|
||||
// submitSuccess for general comments
|
||||
var submitSuccessCallback = function(json_data) {
|
||||
// reload page if we change status for single commit.
|
||||
if (status && self.commitId) {
|
||||
location.reload(true);
|
||||
} else {
|
||||
$('#injected_page_comments').append(o.rendered_text);
|
||||
// inject newly created comments, json_data is {<comment_id>: {}}
|
||||
self.attachGeneralComment(json_data)
|
||||
|
||||
self.resetCommentFormState();
|
||||
timeagoActivate();
|
||||
tooltipActivate();
|
||||
|
|
@ -565,26 +568,6 @@ var CommentsController = function() {
|
|||
var mainComment = '#text';
|
||||
var self = this;
|
||||
|
||||
this.cancelComment = function (node) {
|
||||
var $node = $(node);
|
||||
var edit = $(this).attr('edit');
|
||||
if (edit) {
|
||||
var $general_comments = null;
|
||||
var $inline_comments = $node.closest('div.inline-comments');
|
||||
if (!$inline_comments.length) {
|
||||
$general_comments = $('#comments');
|
||||
var $comment = $general_comments.parent().find('div.comment:hidden');
|
||||
// show hidden general comment form
|
||||
$('#cb-comment-general-form-placeholder').show();
|
||||
} else {
|
||||
var $comment = $inline_comments.find('div.comment:hidden');
|
||||
}
|
||||
$comment.show();
|
||||
}
|
||||
$node.closest('.comment-inline-form').remove();
|
||||
return false;
|
||||
};
|
||||
|
||||
this.showVersion = function (comment_id, comment_history_id) {
|
||||
|
||||
var historyViewUrl = pyroutes.url(
|
||||
|
|
@ -682,6 +665,35 @@ var CommentsController = function() {
|
|||
return self.scrollToComment(node, -1, true);
|
||||
};
|
||||
|
||||
this.cancelComment = function (node) {
|
||||
var $node = $(node);
|
||||
var edit = $(this).attr('edit');
|
||||
var $inlineComments = $node.closest('div.inline-comments');
|
||||
|
||||
if (edit) {
|
||||
var $general_comments = null;
|
||||
if (!$inlineComments.length) {
|
||||
$general_comments = $('#comments');
|
||||
var $comment = $general_comments.parent().find('div.comment:hidden');
|
||||
// show hidden general comment form
|
||||
$('#cb-comment-general-form-placeholder').show();
|
||||
} else {
|
||||
var $comment = $inlineComments.find('div.comment:hidden');
|
||||
}
|
||||
$comment.show();
|
||||
}
|
||||
var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper')
|
||||
$replyWrapper.removeClass('comment-form-active');
|
||||
|
||||
var lastComment = $inlineComments.find('.comment-inline').last();
|
||||
if ($(lastComment).hasClass('comment-outdated')) {
|
||||
$replyWrapper.hide();
|
||||
}
|
||||
|
||||
$node.closest('.comment-inline-form').remove();
|
||||
return false;
|
||||
};
|
||||
|
||||
this._deleteComment = function(node) {
|
||||
var $node = $(node);
|
||||
var $td = $node.closest('td');
|
||||
|
|
@ -751,7 +763,7 @@ var CommentsController = function() {
|
|||
this.finalizeDrafts = function(commentIds) {
|
||||
|
||||
SwalNoAnimation.fire({
|
||||
title: _ngettext('Submit {0} draft comment', 'Submit {0} draft comments', commentIds.length).format(commentIds.length),
|
||||
title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: _gettext('Yes, finalize drafts'),
|
||||
|
|
@ -764,6 +776,7 @@ var CommentsController = function() {
|
|||
};
|
||||
|
||||
this.toggleWideMode = function (node) {
|
||||
|
||||
if ($('#content').hasClass('wrapper')) {
|
||||
$('#content').removeClass("wrapper");
|
||||
$('#content').addClass("wide-mode-wrapper");
|
||||
|
|
@ -778,18 +791,23 @@ var CommentsController = function() {
|
|||
|
||||
};
|
||||
|
||||
this.toggleComments = function(node, show) {
|
||||
/**
|
||||
* Turn off/on all comments in file diff
|
||||
*/
|
||||
this.toggleDiffComments = function(node) {
|
||||
// Find closes filediff container
|
||||
var $filediff = $(node).closest('.filediff');
|
||||
if (show === true) {
|
||||
$filediff.removeClass('hide-comments');
|
||||
} else if (show === false) {
|
||||
$filediff.find('.hide-line-comments').removeClass('hide-line-comments');
|
||||
$filediff.addClass('hide-comments');
|
||||
} else {
|
||||
$filediff.find('.hide-line-comments').removeClass('hide-line-comments');
|
||||
$filediff.toggleClass('hide-comments');
|
||||
if ($(node).hasClass('toggle-on')) {
|
||||
var show = false;
|
||||
} else if ($(node).hasClass('toggle-off')) {
|
||||
var show = true;
|
||||
}
|
||||
|
||||
// Toggle each individual comment block, so we can un-toggle single ones
|
||||
$.each($filediff.find('.toggle-comment-action'), function(idx, val) {
|
||||
self.toggleLineComments($(val), show)
|
||||
})
|
||||
|
||||
// since we change the height of the diff container that has anchor points for upper
|
||||
// sticky header, we need to tell it to re-calculate those
|
||||
if (window.updateSticky !== undefined) {
|
||||
|
|
@ -799,14 +817,33 @@ var CommentsController = function() {
|
|||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
this.toggleLineComments = function(node, show) {
|
||||
|
||||
var trElem = $(node).closest('tr')
|
||||
|
||||
if (show === true) {
|
||||
// mark outdated comments as visible before the toggle;
|
||||
$(trElem).find('.comment-outdated').show();
|
||||
$(trElem).removeClass('hide-line-comments');
|
||||
} else if (show === false) {
|
||||
$(trElem).find('.comment-outdated').hide();
|
||||
$(trElem).addClass('hide-line-comments');
|
||||
} else {
|
||||
// mark outdated comments as visible before the toggle;
|
||||
$(trElem).find('.comment-outdated').show();
|
||||
$(trElem).toggleClass('hide-line-comments');
|
||||
}
|
||||
|
||||
// since we change the height of the diff container that has anchor points for upper
|
||||
// sticky header, we need to tell it to re-calculate those
|
||||
if (window.updateSticky !== undefined) {
|
||||
// potentially our comments change the active window size, so we
|
||||
// notify sticky elements
|
||||
updateSticky()
|
||||
}
|
||||
|
||||
this.toggleLineComments = function(node) {
|
||||
self.toggleComments(node, true);
|
||||
var $node = $(node);
|
||||
// mark outdated comments as visible before the toggle;
|
||||
$(node.closest('tr')).find('.comment-outdated').show();
|
||||
$node.closest('tr').toggleClass('hide-line-comments');
|
||||
};
|
||||
|
||||
this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){
|
||||
|
|
@ -960,64 +997,58 @@ var CommentsController = function() {
|
|||
return commentForm;
|
||||
};
|
||||
|
||||
this.editComment = function(node) {
|
||||
this.editComment = function(node, line_no, f_path) {
|
||||
self.edit = true;
|
||||
var $node = $(node);
|
||||
var $td = $node.closest('td');
|
||||
|
||||
var $comment = $(node).closest('.comment');
|
||||
var comment_id = $($comment).data('commentId');
|
||||
var isDraft = $($comment).data('commentDraft');
|
||||
var $form = null
|
||||
var $editForm = null
|
||||
|
||||
var $comments = $node.closest('div.inline-comments');
|
||||
var $general_comments = null;
|
||||
var lineno = null;
|
||||
|
||||
if($comments.length){
|
||||
// inline comments setup
|
||||
$form = $comments.find('.comment-inline-form');
|
||||
lineno = self.getLineNumber(node)
|
||||
$editForm = $comments.find('.comment-inline-form');
|
||||
line_no = self.getLineNumber(node)
|
||||
}
|
||||
else{
|
||||
// general comments setup
|
||||
$comments = $('#comments');
|
||||
$form = $comments.find('.comment-inline-form');
|
||||
lineno = $comment[0].id
|
||||
$editForm = $comments.find('.comment-inline-form');
|
||||
line_no = $comment[0].id
|
||||
$('#cb-comment-general-form-placeholder').hide();
|
||||
}
|
||||
|
||||
this.edit = true;
|
||||
|
||||
if (!$form.length) {
|
||||
if ($editForm.length === 0) {
|
||||
|
||||
// unhide all comments if they are hidden for a proper REPLY mode
|
||||
var $filediff = $node.closest('.filediff');
|
||||
$filediff.removeClass('hide-comments');
|
||||
var f_path = $filediff.attr('data-f-path');
|
||||
|
||||
// create a new HTML from template
|
||||
$editForm = self.createNewFormWrapper(f_path, line_no);
|
||||
if(f_path && line_no) {
|
||||
$editForm.addClass('comment-inline-form-edit')
|
||||
}
|
||||
|
||||
var tmpl = $('#cb-comment-inline-form-template').html();
|
||||
tmpl = tmpl.format(escapeHtml(f_path), lineno);
|
||||
$form = $(tmpl);
|
||||
$comment.after($form)
|
||||
$comment.after($editForm)
|
||||
|
||||
var _form = $($form[0]).find('form');
|
||||
var _form = $($editForm[0]).find('form');
|
||||
var autocompleteActions = ['as_note',];
|
||||
var commentForm = this.createCommentForm(
|
||||
_form, lineno, '', autocompleteActions, resolvesCommentId,
|
||||
_form, line_no, '', autocompleteActions, resolvesCommentId,
|
||||
this.edit, comment_id);
|
||||
var old_comment_text_binary = $comment.attr('data-comment-text');
|
||||
var old_comment_text = b64DecodeUnicode(old_comment_text_binary);
|
||||
commentForm.cm.setValue(old_comment_text);
|
||||
$comment.hide();
|
||||
tooltipActivate();
|
||||
|
||||
$.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
|
||||
form: _form,
|
||||
parent: $comments,
|
||||
lineno: lineno,
|
||||
f_path: f_path}
|
||||
);
|
||||
|
||||
// set a CUSTOM submit handler for inline comments.
|
||||
commentForm.setHandleFormSubmit(function(o) {
|
||||
// set a CUSTOM submit handler for inline comment edit action.
|
||||
commentForm.setHandleFormSubmit(function(o) {
|
||||
var text = commentForm.cm.getValue();
|
||||
var commentType = commentForm.getCommentType();
|
||||
|
||||
|
|
@ -1048,7 +1079,7 @@ var CommentsController = function() {
|
|||
var postData = {
|
||||
'text': text,
|
||||
'f_path': f_path,
|
||||
'line': lineno,
|
||||
'line': line_no,
|
||||
'comment_type': commentType,
|
||||
'draft': isDraft,
|
||||
'version': version,
|
||||
|
|
@ -1056,7 +1087,7 @@ var CommentsController = function() {
|
|||
};
|
||||
|
||||
var submitSuccessCallback = function(json_data) {
|
||||
$form.remove();
|
||||
$editForm.remove();
|
||||
$comment.show();
|
||||
var postData = {
|
||||
'text': text,
|
||||
|
|
@ -1121,8 +1152,7 @@ var CommentsController = function() {
|
|||
'commit_id': templateContext.commit_data.commit_id});
|
||||
|
||||
_submitAjaxPOST(
|
||||
previewUrl, postData, successRenderCommit,
|
||||
failRenderCommit
|
||||
previewUrl, postData, successRenderCommit, failRenderCommit
|
||||
);
|
||||
|
||||
try {
|
||||
|
|
@ -1178,49 +1208,103 @@ var CommentsController = function() {
|
|||
});
|
||||
}
|
||||
|
||||
$form.addClass('comment-inline-form-open');
|
||||
$editForm.addClass('comment-inline-form-open');
|
||||
};
|
||||
|
||||
this.createComment = function(node, resolutionComment) {
|
||||
var resolvesCommentId = resolutionComment || null;
|
||||
this.attachComment = function(json_data) {
|
||||
var self = this;
|
||||
$.each(json_data, function(idx, val) {
|
||||
var json_data_elem = [val]
|
||||
var isInline = val.comment_f_path && val.comment_lineno
|
||||
|
||||
if (isInline) {
|
||||
self.attachInlineComment(json_data_elem)
|
||||
} else {
|
||||
self.attachGeneralComment(json_data_elem)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
this.attachGeneralComment = function(json_data) {
|
||||
$.each(json_data, function(idx, val) {
|
||||
$('#injected_page_comments').append(val.rendered_text);
|
||||
})
|
||||
}
|
||||
|
||||
this.attachInlineComment = function(json_data) {
|
||||
|
||||
$.each(json_data, function (idx, val) {
|
||||
var line_qry = '*[data-line-no="{0}"]'.format(val.line_no);
|
||||
var html = val.rendered_text;
|
||||
var $inlineComments = $('#' + val.target_id)
|
||||
.find(line_qry)
|
||||
.find('.inline-comments');
|
||||
|
||||
var lastComment = $inlineComments.find('.comment-inline').last();
|
||||
|
||||
if (lastComment.length === 0) {
|
||||
// first comment, we append simply
|
||||
$inlineComments.find('.reply-thread-container-wrapper').before(html);
|
||||
} else {
|
||||
$(lastComment).after(html)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
this.createNewFormWrapper = function(f_path, line_no) {
|
||||
// create a new reply HTML form from template
|
||||
var tmpl = $('#cb-comment-inline-form-template').html();
|
||||
tmpl = tmpl.format(escapeHtml(f_path), line_no);
|
||||
return $(tmpl);
|
||||
}
|
||||
|
||||
this.createComment = function(node, f_path, line_no, resolutionComment) {
|
||||
self.edit = false;
|
||||
var $node = $(node);
|
||||
var $td = $node.closest('td');
|
||||
var $form = $td.find('.comment-inline-form');
|
||||
this.edit = false;
|
||||
var resolvesCommentId = resolutionComment || null;
|
||||
|
||||
if (!$form.length) {
|
||||
var $replyForm = $td.find('.comment-inline-form');
|
||||
|
||||
var $filediff = $node.closest('.filediff');
|
||||
$filediff.removeClass('hide-comments');
|
||||
var f_path = $filediff.attr('data-f-path');
|
||||
var lineno = self.getLineNumber(node);
|
||||
// create a new HTML from template
|
||||
var tmpl = $('#cb-comment-inline-form-template').html();
|
||||
tmpl = tmpl.format(escapeHtml(f_path), lineno);
|
||||
$form = $(tmpl);
|
||||
// if form isn't existing, we're generating a new one and injecting it.
|
||||
if ($replyForm.length === 0) {
|
||||
|
||||
// unhide/expand all comments if they are hidden for a proper REPLY mode
|
||||
self.toggleLineComments($node, true);
|
||||
|
||||
$replyForm = self.createNewFormWrapper(f_path, line_no);
|
||||
|
||||
var $comments = $td.find('.inline-comments');
|
||||
if (!$comments.length) {
|
||||
$comments = $(
|
||||
$('#cb-comments-inline-container-template').html());
|
||||
$td.append($comments);
|
||||
|
||||
// There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first
|
||||
if ($comments.length===0) {
|
||||
var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(f_path, line_no)
|
||||
var $reply_container = $('#cb-comments-inline-container-template')
|
||||
$reply_container.find('button.cb-comment-add-button').replaceWith(replBtn);
|
||||
$td.append($($reply_container).html());
|
||||
}
|
||||
|
||||
$td.find('.cb-comment-add-button').before($form);
|
||||
// default comment button exists, so we prepend the form for leaving initial comment
|
||||
$td.find('.cb-comment-add-button').before($replyForm);
|
||||
// set marker, that we have a open form
|
||||
var $replyWrapper = $td.find('.reply-thread-container-wrapper')
|
||||
$replyWrapper.addClass('comment-form-active');
|
||||
|
||||
var placeholderText = _gettext('Leave a comment on line {0}.').format(lineno);
|
||||
var _form = $($form[0]).find('form');
|
||||
var lastComment = $comments.find('.comment-inline').last();
|
||||
if ($(lastComment).hasClass('comment-outdated')) {
|
||||
$replyWrapper.show();
|
||||
}
|
||||
|
||||
var _form = $($replyForm[0]).find('form');
|
||||
var autocompleteActions = ['as_note', 'as_todo'];
|
||||
var comment_id=null;
|
||||
var commentForm = this.createCommentForm(
|
||||
_form, lineno, placeholderText, autocompleteActions, resolvesCommentId, this.edit, comment_id);
|
||||
|
||||
$.Topic('/ui/plugins/code/comment_form_built').prepareOrPublish({
|
||||
form: _form,
|
||||
parent: $td[0],
|
||||
lineno: lineno,
|
||||
f_path: f_path}
|
||||
);
|
||||
var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no);
|
||||
var commentForm = self.createCommentForm(
|
||||
_form, line_no, placeholderText, autocompleteActions, resolvesCommentId,
|
||||
self.edit, comment_id);
|
||||
|
||||
// set a CUSTOM submit handler for inline comments.
|
||||
commentForm.setHandleFormSubmit(function(o) {
|
||||
|
|
@ -1233,12 +1317,13 @@ var CommentsController = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (lineno === undefined) {
|
||||
alert('missing line !');
|
||||
if (line_no === undefined) {
|
||||
alert('Error: unable to fetch line number for this inline comment !');
|
||||
return;
|
||||
}
|
||||
|
||||
if (f_path === undefined) {
|
||||
alert('missing file path !');
|
||||
alert('Error: unable to fetch file path for this inline comment !');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1249,7 +1334,7 @@ var CommentsController = function() {
|
|||
var postData = {
|
||||
'text': text,
|
||||
'f_path': f_path,
|
||||
'line': lineno,
|
||||
'line': line_no,
|
||||
'comment_type': commentType,
|
||||
'draft': isDraft,
|
||||
'csrf_token': CSRF_TOKEN
|
||||
|
|
@ -1258,32 +1343,32 @@ var CommentsController = function() {
|
|||
postData['resolves_comment_id'] = resolvesCommentId;
|
||||
}
|
||||
|
||||
// submitSuccess for inline commits
|
||||
var submitSuccessCallback = function(json_data) {
|
||||
$form.remove();
|
||||
try {
|
||||
var html = json_data.rendered_text;
|
||||
var lineno = json_data.line_no;
|
||||
var target_id = json_data.target_id;
|
||||
|
||||
$comments.find('.cb-comment-add-button').before(html);
|
||||
$replyForm.remove();
|
||||
$td.find('.reply-thread-container-wrapper').removeClass('comment-form-active');
|
||||
|
||||
//mark visually which comment was resolved
|
||||
if (resolvesCommentId) {
|
||||
commentForm.markCommentResolved(resolvesCommentId);
|
||||
try {
|
||||
|
||||
// inject newly created comments, json_data is {<comment_id>: {}}
|
||||
self.attachInlineComment(json_data)
|
||||
|
||||
//mark visually which comment was resolved
|
||||
if (resolvesCommentId) {
|
||||
commentForm.markCommentResolved(resolvesCommentId);
|
||||
}
|
||||
|
||||
// run global callback on submit
|
||||
commentForm.globalSubmitSuccessCallback({
|
||||
draft: isDraft,
|
||||
comment_id: comment_id
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
// run global callback on submit
|
||||
commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
// re trigger the linkification of next/prev navigation
|
||||
linkifyComments($('.inline-comment-injected'));
|
||||
timeagoActivate();
|
||||
tooltipActivate();
|
||||
|
||||
if (window.updateSticky !== undefined) {
|
||||
// potentially our comments change the active window size, so we
|
||||
// notify sticky elements
|
||||
|
|
@ -1297,19 +1382,27 @@ var CommentsController = function() {
|
|||
|
||||
commentForm.setActionButtonsDisabled(false);
|
||||
|
||||
// re trigger the linkification of next/prev navigation
|
||||
linkifyComments($('.inline-comment-injected'));
|
||||
timeagoActivate();
|
||||
tooltipActivate();
|
||||
};
|
||||
|
||||
var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
|
||||
var prefix = "Error while submitting comment.\n"
|
||||
var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
|
||||
ajaxErrorSwal(message);
|
||||
commentForm.resetCommentFormState(text)
|
||||
};
|
||||
|
||||
commentForm.submitAjaxPOST(
|
||||
commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
|
||||
});
|
||||
}
|
||||
|
||||
$form.addClass('comment-inline-form-open');
|
||||
// Finally "open" our reply form, since we know there are comments and we have the "attached" old form
|
||||
$replyForm.addClass('comment-inline-form-open');
|
||||
tooltipActivate();
|
||||
};
|
||||
|
||||
this.createResolutionComment = function(commentId){
|
||||
|
|
@ -1319,9 +1412,12 @@ var CommentsController = function() {
|
|||
var comment = $('#comment-'+commentId);
|
||||
var commentData = comment.data();
|
||||
if (commentData.commentInline) {
|
||||
this.createComment(comment, commentId)
|
||||
var f_path = commentData.fPath;
|
||||
var line_no = commentData.lineNo;
|
||||
//TODO check this if we need to give f_path/line_no
|
||||
this.createComment(comment, f_path, line_no, commentId)
|
||||
} else {
|
||||
Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
|
||||
this.createGeneralComment('general', "$placeholder", commentId)
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -1347,3 +1443,8 @@ var CommentsController = function() {
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
window.commentHelp = function(renderer) {
|
||||
var funcData = {'renderer': renderer}
|
||||
return renderTemplate('commentHelpHovercard', funcData)
|
||||
}
|
||||
|
|
@ -42,12 +42,22 @@ window.toggleElement = function (elem, target) {
|
|||
var $elem = $(elem);
|
||||
var $target = $(target);
|
||||
|
||||
if ($target.is(':visible') || $target.length === 0) {
|
||||
if (target !== undefined) {
|
||||
var show = $target.is(':visible') || $target.length === 0;
|
||||
} else {
|
||||
var show = $elem.hasClass('toggle-off')
|
||||
}
|
||||
|
||||
if (show) {
|
||||
$target.hide();
|
||||
$elem.html($elem.data('toggleOn'))
|
||||
$elem.addClass('toggle-on')
|
||||
$elem.removeClass('toggle-off')
|
||||
} else {
|
||||
$target.show();
|
||||
$elem.html($elem.data('toggleOff'))
|
||||
$elem.addClass('toggle-off')
|
||||
$elem.removeClass('toggle-on')
|
||||
}
|
||||
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/__MAIN_APP__ - launched when rhodecode-app element is attached to DOM
|
||||
/plugins/__REGISTER__ - launched after the onDomReady() code from rhodecode.js is executed
|
||||
/ui/plugins/code/anchor_focus - launched when rc starts to scroll on load to anchor on PR/Codeview
|
||||
/ui/plugins/code/comment_form_built - launched when injectInlineForm() is executed and the form object is created
|
||||
/notifications - shows new event notifications
|
||||
/connection_controller/subscribe - subscribes user to new channels
|
||||
/connection_controller/presence - receives presence change messages
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
## this is a dummy html file for partial rendering on server and sending
|
||||
## generated output via ajax after comment submit
|
||||
<%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
|
||||
${comment.comment_block(c.co, inline=c.co.is_inline)}
|
||||
${comment.comment_block(c.co, inline=c.co.is_inline, is_new=c.is_new)}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
%>
|
||||
|
||||
|
||||
<%def name="comment_block(comment, inline=False, active_pattern_entries=None)">
|
||||
<%def name="comment_block(comment, inline=False, active_pattern_entries=None, is_new=False)">
|
||||
|
||||
<%
|
||||
from rhodecode.model.comment import CommentsModel
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
data-comment-draft=${h.json.dumps(comment.draft)}
|
||||
data-comment-renderer="${comment.renderer}"
|
||||
data-comment-text="${comment.text | html_filters.base64,n}"
|
||||
data-comment-f-path="${comment.f_path}"
|
||||
data-comment-line-no="${comment.line_no}"
|
||||
data-comment-inline=${h.json.dumps(inline)}
|
||||
style="${'display: none;' if outdated_at_ver else ''}">
|
||||
|
|
@ -47,8 +48,17 @@
|
|||
<div class="meta">
|
||||
<div class="comment-type-label">
|
||||
% if comment.draft:
|
||||
<div class="tooltip comment-draft" title="${_('Draft comments are only visible to the author until submitted')}.">DRAFT</div>
|
||||
<div class="tooltip comment-draft" title="${_('Draft comments are only visible to the author until submitted')}.">
|
||||
DRAFT
|
||||
</div>
|
||||
% endif
|
||||
|
||||
% if is_new:
|
||||
<div class="tooltip comment-new" title="${_('This comment was added while you browsed this page')}.">
|
||||
NEW
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}">
|
||||
|
||||
## TODO COMMENT
|
||||
|
|
@ -176,7 +186,7 @@
|
|||
% if inline:
|
||||
<a class="pr-version-inline" href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}">
|
||||
% if outdated_at_ver:
|
||||
<code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">outdated ${'v{}'.format(comment_ver)}</code>
|
||||
<strong class="comment-outdated-label">outdated</strong> <code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code>
|
||||
<code class="action-divider">|</code>
|
||||
% elif comment_ver:
|
||||
<code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code>
|
||||
|
|
@ -222,12 +232,13 @@
|
|||
%if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id):
|
||||
<div class="dropdown-divider"></div>
|
||||
<div class="dropdown-item">
|
||||
<a onclick="return Rhodecode.comments.editComment(this);" class="btn btn-link btn-sm edit-comment">${_('Edit')}</a>
|
||||
<a onclick="return Rhodecode.comments.editComment(this, '${comment.line_no}', '${comment.f_path}');" class="btn btn-link btn-sm edit-comment">${_('Edit')}</a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a onclick="return Rhodecode.comments.deleteComment(this);" class="btn btn-link btn-sm btn-danger delete-comment">${_('Delete')}</a>
|
||||
</div>
|
||||
% if comment.draft:
|
||||
## Only available in EE edition
|
||||
% if comment.draft and c.rhodecode_edition_id == 'EE':
|
||||
<div class="dropdown-item">
|
||||
<a onclick="return Rhodecode.comments.finalizeDrafts([${comment.comment_id}]);" class="btn btn-link btn-sm finalize-draft-comment">${_('Submit draft')}</a>
|
||||
</div>
|
||||
|
|
@ -391,7 +402,7 @@
|
|||
|
||||
<div class="comment-area-write" style="display: block;">
|
||||
<div id="edit-container">
|
||||
<div style="padding: 40px 0">
|
||||
<div style="padding: 20px 0px 0px 0;">
|
||||
${_('You need to be logged in to leave comments.')}
|
||||
<a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
|
||||
</div>
|
||||
|
|
@ -450,7 +461,7 @@
|
|||
</div>
|
||||
|
||||
<div class="comment-area-write" style="display: block;">
|
||||
<div id="edit-container_${lineno_id}">
|
||||
<div id="edit-container_${lineno_id}" style="margin-top: -1px">
|
||||
<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;">
|
||||
|
|
@ -500,40 +511,47 @@
|
|||
<input class="btn btn-success comment-button-input submit-comment-action" id="save_${lineno_id}" name="save" type="submit" value="${_('Add comment')}" data-is-draft=false onclick="$(this).addClass('submitter')">
|
||||
|
||||
% if form_type == 'inline':
|
||||
<input class="btn btn-warning comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')">
|
||||
% if c.rhodecode_edition_id == 'EE':
|
||||
## Disable the button for CE, the "real" validation is in the backend code anyway
|
||||
<input class="btn btn-warning comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')">
|
||||
% else:
|
||||
<input class="tooltip btn btn-warning comment-button-input submit-draft-action disabled" type="submit" disabled="disabled" value="${_('Add draft')}" onclick="return false;" title="Draft comments only available in EE edition of RhodeCode">
|
||||
% endif
|
||||
% endif
|
||||
|
||||
% if review_statuses:
|
||||
<div class="comment-status-box">
|
||||
<select id="change_status_${lineno_id}" name="changeset_status">
|
||||
<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
|
||||
|
||||
## 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="tooltip cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);" title="Hide comment box">
|
||||
<button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
|
||||
<i class="icon-cancel-circled2"></i>
|
||||
</button>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
% if review_statuses:
|
||||
<div class="status_box">
|
||||
<select id="change_status_${lineno_id}" name="changeset_status">
|
||||
<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
|
||||
|
||||
<div class="toolbar-text">
|
||||
<% renderer_url = '<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper()) %>
|
||||
${_('Comments parsed using {} syntax.').format(renderer_url)|n} <br/>
|
||||
<span class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span>
|
||||
${_('and')}
|
||||
<span class="tooltip" title="${_('Start typing with / for certain actions to be triggered via text box.')}">`/` autocomplete</span>
|
||||
${_('actions supported.')}
|
||||
<p>${_('Styling with {} is supported.').format(renderer_url)|n}
|
||||
|
||||
<i class="icon-info-circled tooltip-hovercard"
|
||||
data-hovercard-alt="ALT"
|
||||
data-hovercard-url="javascript:commentHelp('${c.visual.default_renderer.upper()}')"
|
||||
data-comment-json-b64='${h.b64(h.json.dumps({}))}'></i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<%namespace name="base" file="/base/base.mako"/>
|
||||
<%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
|
||||
|
||||
<%def name="diff_line_anchor(commit, filename, line, type)"><%
|
||||
|
|
@ -74,24 +75,9 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
|
||||
<div class="js-template" id="cb-comment-inline-form-template">
|
||||
<div class="comment-inline-form ac">
|
||||
|
||||
%if c.rhodecode_user.username != h.DEFAULT_USER:
|
||||
%if not c.rhodecode_user.is_default:
|
||||
## render template for inline comments
|
||||
${commentblock.comment_form(form_type='inline')}
|
||||
%else:
|
||||
${h.form('', class_='inline-form comment-form-login', method='get')}
|
||||
<div class="pull-left">
|
||||
<div class="comment-help pull-right">
|
||||
${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-button pull-right">
|
||||
<button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
|
||||
${_('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
${h.end_form()}
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -327,7 +313,7 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
</label>
|
||||
|
||||
${diff_menu(filediff, use_comments=use_comments)}
|
||||
<table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
|
||||
<table id="file-${h.safeid(h.safe_unicode(filediff.patch['filename']))}" data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
|
||||
|
||||
## new/deleted/empty content case
|
||||
% if not filediff.hunks:
|
||||
|
|
@ -626,8 +612,10 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
|
||||
% if use_comments:
|
||||
|
|
||||
<a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
|
||||
<span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
|
||||
<a href="#" onclick="Rhodecode.comments.toggleDiffComments(this);return toggleElement(this)"
|
||||
data-toggle-on="${_('Hide comments')}"
|
||||
data-toggle-off="${_('Show comments')}">
|
||||
<span class="hide-comment-button">${_('Hide comments')}</span>
|
||||
</a>
|
||||
% endif
|
||||
|
||||
|
|
@ -637,23 +625,36 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
</%def>
|
||||
|
||||
|
||||
<%def name="inline_comments_container(comments, active_pattern_entries=None)">
|
||||
<%def name="inline_comments_container(comments, active_pattern_entries=None, line_no='', f_path='')">
|
||||
|
||||
<div class="inline-comments">
|
||||
%for comment in comments:
|
||||
${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)}
|
||||
%endfor
|
||||
% if comments and comments[-1].outdated:
|
||||
<span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}">
|
||||
${_('Add another comment')}
|
||||
</span>
|
||||
% else:
|
||||
<span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button">
|
||||
${_('Add another comment')}
|
||||
</span>
|
||||
% endif
|
||||
|
||||
<%
|
||||
extra_class = ''
|
||||
extra_style = ''
|
||||
|
||||
if comments and comments[-1].outdated:
|
||||
extra_class = ' comment-outdated'
|
||||
extra_style = 'display: none;'
|
||||
|
||||
%>
|
||||
<div class="reply-thread-container-wrapper${extra_class}" style="${extra_style}">
|
||||
<div class="reply-thread-container${extra_class}">
|
||||
<div class="reply-thread-gravatar">
|
||||
${base.gravatar(c.rhodecode_user.email, 20, tooltip=True, user=c.rhodecode_user)}
|
||||
</div>
|
||||
<div class="reply-thread-reply-button">
|
||||
## initial reply button, some JS logic can append here a FORM to leave a first comment.
|
||||
<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)">Reply...</button>
|
||||
</div>
|
||||
<div class="reply-thread-last"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</%def>
|
||||
|
||||
<%!
|
||||
|
|
@ -721,9 +722,9 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
%endif
|
||||
%if line_old_comments_no_drafts:
|
||||
% if has_outdated:
|
||||
<i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% endif
|
||||
%endif
|
||||
</td>
|
||||
|
|
@ -737,16 +738,18 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
<a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
|
||||
%endif
|
||||
</td>
|
||||
|
||||
<% line_no = 'o{}'.format(line.original.lineno) %>
|
||||
<td class="cb-content ${action_class(line.original.action)}"
|
||||
data-line-no="o${line.original.lineno}"
|
||||
data-line-no="${line_no}"
|
||||
>
|
||||
%if use_comments and line.original.lineno:
|
||||
${render_add_comment_button()}
|
||||
${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
<span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span>
|
||||
|
||||
%if use_comments and line.original.lineno and line_old_comments:
|
||||
${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries)}
|
||||
${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
|
||||
</td>
|
||||
|
|
@ -766,9 +769,9 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
|
||||
%if line_new_comments_no_drafts:
|
||||
% if has_outdated:
|
||||
<i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% endif
|
||||
%endif
|
||||
</div>
|
||||
|
|
@ -783,22 +786,25 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
<a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
|
||||
%endif
|
||||
</td>
|
||||
|
||||
<% line_no = 'n{}'.format(line.modified.lineno) %>
|
||||
<td class="cb-content ${action_class(line.modified.action)}"
|
||||
data-line-no="n${line.modified.lineno}"
|
||||
data-line-no="${line_no}"
|
||||
>
|
||||
%if use_comments and line.modified.lineno:
|
||||
${render_add_comment_button()}
|
||||
${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
<span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span>
|
||||
%if use_comments and line.modified.lineno and line_new_comments:
|
||||
${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)}
|
||||
%endif
|
||||
% if line_action in ['+', '-'] and prev_line_action not in ['+', '-']:
|
||||
<div class="nav-chunk" style="visibility: hidden">
|
||||
<i class="icon-eye" title="viewing diff hunk-${hunk.index}-${chunk_count}"></i>
|
||||
</div>
|
||||
<% chunk_count +=1 %>
|
||||
% endif
|
||||
%if use_comments and line.modified.lineno and line_new_comments:
|
||||
${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
|
|
@ -830,9 +836,9 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
|
||||
% if comments_no_drafts:
|
||||
% if has_outdated:
|
||||
<i class="tooltip icon-comment-toggle" title="${_('comments including outdated: {}. Click here to display them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
<i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
|
|
@ -857,15 +863,16 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
<a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
|
||||
%endif
|
||||
</td>
|
||||
<% line_no = '{}{}'.format(new_line_no and 'n' or 'o', new_line_no or old_line_no) %>
|
||||
<td class="cb-content ${action_class(action)}"
|
||||
data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}"
|
||||
data-line-no="${line_no}"
|
||||
>
|
||||
%if use_comments:
|
||||
${render_add_comment_button()}
|
||||
${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
<span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span>
|
||||
%if use_comments and comments:
|
||||
${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
|
||||
${inline_comments_container(comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])}
|
||||
%endif
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -886,10 +893,12 @@ def get_comments_for(diff_type, comments, filename, line_version, line_number):
|
|||
</%def>file changes
|
||||
|
||||
|
||||
<%def name="render_add_comment_button()">
|
||||
<button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)">
|
||||
<%def name="render_add_comment_button(line_no='', f_path='')">
|
||||
% if not c.rhodecode_user.is_default:
|
||||
<button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)">
|
||||
<span><i class="icon-comment"></i></span>
|
||||
</button>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="render_diffset_menu(diffset, range_diff_on=None, commit=None, pull_request_menu=None)">
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ ${h.style_metatag(tag_type, tag)|n,trim}
|
|||
</div>
|
||||
|
||||
<div class="markup-form-area-write" style="display: block;">
|
||||
<div id="edit-container_${form_id}">
|
||||
<div id="edit-container_${form_id}" style="margin-top: -1px">
|
||||
<textarea id="${form_id}" name="${form_id}" class="comment-block-ta ac-input">${form_text if form_text else ''}</textarea>
|
||||
</div>
|
||||
<div id="preview-container_${form_id}" class="clearfix" style="display: none;">
|
||||
|
|
|
|||
|
|
@ -237,6 +237,24 @@ if (show_disabled) {
|
|||
|
||||
</script>
|
||||
|
||||
<script id="ejs_commentHelpHovercard" type="text/template" class="ejsTemplate">
|
||||
|
||||
<div>
|
||||
Use <strong>@username</strong> mention syntax to send direct notification to this RhodeCode user.<br/>
|
||||
Typing / starts autocomplete for certain action, e.g set review status, or comment type. <br/>
|
||||
<br/>
|
||||
Use <strong>Cmd/ctrl+enter</strong> to submit comment, or <strong>Shift+Cmd/ctrl+enter</strong> to submit a draft.<br/>
|
||||
<br/>
|
||||
<strong>Draft comments</strong> are private to the author, and trigger no notification to others.<br/>
|
||||
They are permanent until deleted, or converted to regular comments.<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
##// END OF EJS Templates
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -846,6 +846,7 @@ versionController.init();
|
|||
|
||||
reviewersController = new ReviewersController();
|
||||
commitsController = new CommitsController();
|
||||
commentsController = new CommentsController();
|
||||
|
||||
updateController = new UpdatePrController();
|
||||
|
||||
|
|
@ -1002,6 +1003,8 @@ $(document).ready(function () {
|
|||
alert('okok !' + commentIds)
|
||||
|
||||
}
|
||||
// register globally so inject comment logic can re-use it.
|
||||
window.commentsController = commentsController;
|
||||
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue