pull-requests: overhaul of the UX by adding new sidebar
- sidebar aggregates comments, todos, observers, referenced tickets, and reviewers - live components push now comments, reviewer presence, and todo live via channelstream - sidebar is collapsable, and stored in user session - simplified number of information on the pull request page - fixed and cleanup of the outdated comments and at version comments that in some cases reported wrong version assignment.
This commit is contained in:
parent
9106e99baf
commit
9430615145
18 changed files with 1132 additions and 639 deletions
|
|
@ -345,6 +345,16 @@ def includeme(config):
|
|||
pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
|
||||
repo_route=True, repo_accepted_types=['hg', 'git'])
|
||||
|
||||
config.add_route(
|
||||
name='pullrequest_comments',
|
||||
pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comments',
|
||||
repo_route=True)
|
||||
|
||||
config.add_route(
|
||||
name='pullrequest_todos',
|
||||
pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos',
|
||||
repo_route=True)
|
||||
|
||||
# Artifacts, (EE feature)
|
||||
config.add_route(
|
||||
name='repo_artifacts_list',
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ class RepoCommitsView(RepoAppView):
|
|||
diff_limit = c.visual.cut_off_limit_diff
|
||||
file_limit = c.visual.cut_off_limit_file
|
||||
|
||||
|
||||
# get ranges of commit ids if preset
|
||||
commit_range = commit_id_range.split('...')[:2]
|
||||
|
||||
|
|
@ -226,6 +227,7 @@ class RepoCommitsView(RepoAppView):
|
|||
|
||||
# sort comments by how they were generated
|
||||
c.comments = sorted(c.comments, key=lambda x: x.comment_id)
|
||||
c.at_version_num = None
|
||||
|
||||
if len(c.commit_ranges) == 1:
|
||||
c.commit = c.commit_ranges[0]
|
||||
|
|
|
|||
|
|
@ -265,6 +265,36 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
return diffset
|
||||
|
||||
def register_comments_vars(self, c, pull_request, versions):
|
||||
comments_model = CommentsModel()
|
||||
|
||||
# GENERAL COMMENTS with versions #
|
||||
q = comments_model._all_general_comments_of_pull_request(pull_request)
|
||||
q = q.order_by(ChangesetComment.comment_id.asc())
|
||||
general_comments = q
|
||||
|
||||
# pick comments we want to render at current version
|
||||
c.comment_versions = comments_model.aggregate_comments(
|
||||
general_comments, versions, c.at_version_num)
|
||||
|
||||
# INLINE COMMENTS with versions #
|
||||
q = comments_model._all_inline_comments_of_pull_request(pull_request)
|
||||
q = q.order_by(ChangesetComment.comment_id.asc())
|
||||
inline_comments = q
|
||||
|
||||
c.inline_versions = comments_model.aggregate_comments(
|
||||
inline_comments, versions, c.at_version_num, inline=True)
|
||||
|
||||
# Comments inline+general
|
||||
if c.at_version:
|
||||
c.inline_comments_flat = c.inline_versions[c.at_version_num]['display']
|
||||
c.comments = c.comment_versions[c.at_version_num]['display']
|
||||
else:
|
||||
c.inline_comments_flat = c.inline_versions[c.at_version_num]['until']
|
||||
c.comments = c.comment_versions[c.at_version_num]['until']
|
||||
|
||||
return general_comments, inline_comments
|
||||
|
||||
@LoginRequired()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
|
|
@ -280,6 +310,8 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
pull_request_id = pull_request.pull_request_id
|
||||
|
||||
c.state_progressing = pull_request.is_state_changing()
|
||||
c.pr_broadcast_channel = '/repo${}$/pr/{}'.format(
|
||||
pull_request.target_repo.repo_name, pull_request.pull_request_id)
|
||||
|
||||
_new_state = {
|
||||
'created': PullRequest.STATE_CREATED,
|
||||
|
|
@ -300,22 +332,23 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
from_version = self.request.GET.get('from_version') or version
|
||||
merge_checks = self.request.GET.get('merge_checks')
|
||||
c.fulldiff = str2bool(self.request.GET.get('fulldiff'))
|
||||
force_refresh = str2bool(self.request.GET.get('force_refresh'))
|
||||
c.range_diff_on = self.request.GET.get('range-diff') == "1"
|
||||
|
||||
# fetch global flags of ignore ws or context lines
|
||||
diff_context = diffs.get_diff_context(self.request)
|
||||
hide_whitespace_changes = diffs.get_diff_whitespace_flag(self.request)
|
||||
|
||||
force_refresh = str2bool(self.request.GET.get('force_refresh'))
|
||||
|
||||
(pull_request_latest,
|
||||
pull_request_at_ver,
|
||||
pull_request_display_obj,
|
||||
at_version) = PullRequestModel().get_pr_version(
|
||||
pull_request_id, version=version)
|
||||
|
||||
pr_closed = pull_request_latest.is_closed()
|
||||
|
||||
if pr_closed and (version or from_version):
|
||||
# not allow to browse versions
|
||||
# not allow to browse versions for closed PR
|
||||
raise HTTPFound(h.route_path(
|
||||
'pullrequest_show', repo_name=self.db_repo_name,
|
||||
pull_request_id=pull_request_id))
|
||||
|
|
@ -323,13 +356,13 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
versions = pull_request_display_obj.versions()
|
||||
# used to store per-commit range diffs
|
||||
c.changes = collections.OrderedDict()
|
||||
c.range_diff_on = self.request.GET.get('range-diff') == "1"
|
||||
|
||||
c.at_version = at_version
|
||||
c.at_version_num = (at_version
|
||||
if at_version and at_version != 'latest'
|
||||
if at_version and at_version != PullRequest.LATEST_VER
|
||||
else None)
|
||||
c.at_version_pos = ChangesetComment.get_index_from_version(
|
||||
|
||||
c.at_version_index = ChangesetComment.get_index_from_version(
|
||||
c.at_version_num, versions)
|
||||
|
||||
(prev_pull_request_latest,
|
||||
|
|
@ -340,9 +373,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
c.from_version = prev_at_version
|
||||
c.from_version_num = (prev_at_version
|
||||
if prev_at_version and prev_at_version != 'latest'
|
||||
if prev_at_version and prev_at_version != PullRequest.LATEST_VER
|
||||
else None)
|
||||
c.from_version_pos = ChangesetComment.get_index_from_version(
|
||||
c.from_version_index = ChangesetComment.get_index_from_version(
|
||||
c.from_version_num, versions)
|
||||
|
||||
# define if we're in COMPARE mode or VIEW at version mode
|
||||
|
|
@ -355,14 +388,17 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
self.db_repo_name, pull_request_at_ver.target_repo.repo_name)
|
||||
raise HTTPNotFound()
|
||||
|
||||
c.shadow_clone_url = PullRequestModel().get_shadow_clone_url(
|
||||
pull_request_at_ver)
|
||||
c.shadow_clone_url = PullRequestModel().get_shadow_clone_url(pull_request_at_ver)
|
||||
|
||||
c.pull_request = pull_request_display_obj
|
||||
c.renderer = pull_request_at_ver.description_renderer or c.renderer
|
||||
c.pull_request_latest = pull_request_latest
|
||||
|
||||
if compare or (at_version and not at_version == 'latest'):
|
||||
# inject latest version
|
||||
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
|
||||
c.versions = versions + [latest_ver]
|
||||
|
||||
if compare or (at_version and not at_version == PullRequest.LATEST_VER):
|
||||
c.allowed_to_change_status = False
|
||||
c.allowed_to_update = False
|
||||
c.allowed_to_merge = False
|
||||
|
|
@ -391,12 +427,9 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
'rules' in pull_request_latest.reviewer_data:
|
||||
rules = pull_request_latest.reviewer_data['rules'] or {}
|
||||
try:
|
||||
c.forbid_adding_reviewers = rules.get(
|
||||
'forbid_adding_reviewers')
|
||||
c.forbid_author_to_review = rules.get(
|
||||
'forbid_author_to_review')
|
||||
c.forbid_commit_author_to_review = rules.get(
|
||||
'forbid_commit_author_to_review')
|
||||
c.forbid_adding_reviewers = rules.get('forbid_adding_reviewers')
|
||||
c.forbid_author_to_review = rules.get('forbid_author_to_review')
|
||||
c.forbid_commit_author_to_review = rules.get('forbid_commit_author_to_review')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
@ -421,41 +454,37 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
'rhodecode:templates/pullrequests/pullrequest_merge_checks.mako'
|
||||
return self._get_template_context(c)
|
||||
|
||||
comments_model = CommentsModel()
|
||||
c.allowed_reviewers = [obj.user_id for obj in pull_request.reviewers if obj.user]
|
||||
|
||||
# reviewers and statuses
|
||||
c.pull_request_reviewers = pull_request_at_ver.reviewers_statuses()
|
||||
allowed_reviewers = [x[0].user_id for x in c.pull_request_reviewers]
|
||||
c.pull_request_default_reviewers_data_json = json.dumps(pull_request.reviewer_data)
|
||||
c.pull_request_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
|
||||
|
||||
# GENERAL COMMENTS with versions #
|
||||
q = comments_model._all_general_comments_of_pull_request(pull_request_latest)
|
||||
q = q.order_by(ChangesetComment.comment_id.asc())
|
||||
general_comments = q
|
||||
for review_obj, member, reasons, mandatory, status in pull_request_at_ver.reviewers_statuses():
|
||||
member_reviewer = h.reviewer_as_json(
|
||||
member, reasons=reasons, mandatory=mandatory,
|
||||
user_group=review_obj.rule_user_group_data()
|
||||
)
|
||||
|
||||
# pick comments we want to render at current version
|
||||
c.comment_versions = comments_model.aggregate_comments(
|
||||
general_comments, versions, c.at_version_num)
|
||||
c.comments = c.comment_versions[c.at_version_num]['until']
|
||||
current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED
|
||||
member_reviewer['review_status'] = current_review_status
|
||||
member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status)
|
||||
member_reviewer['allowed_to_update'] = c.allowed_to_update
|
||||
c.pull_request_set_reviewers_data_json['reviewers'].append(member_reviewer)
|
||||
|
||||
# INLINE COMMENTS with versions #
|
||||
q = comments_model._all_inline_comments_of_pull_request(pull_request_latest)
|
||||
q = q.order_by(ChangesetComment.comment_id.asc())
|
||||
inline_comments = q
|
||||
c.pull_request_set_reviewers_data_json = json.dumps(c.pull_request_set_reviewers_data_json)
|
||||
|
||||
c.inline_versions = comments_model.aggregate_comments(
|
||||
inline_comments, versions, c.at_version_num, inline=True)
|
||||
|
||||
|
||||
|
||||
general_comments, inline_comments = \
|
||||
self.register_comments_vars(c, pull_request_latest, versions)
|
||||
|
||||
# TODOs
|
||||
c.unresolved_comments = CommentsModel() \
|
||||
.get_pull_request_unresolved_todos(pull_request)
|
||||
.get_pull_request_unresolved_todos(pull_request_latest)
|
||||
c.resolved_comments = CommentsModel() \
|
||||
.get_pull_request_resolved_todos(pull_request)
|
||||
|
||||
# inject latest version
|
||||
latest_ver = PullRequest.get_pr_display_object(
|
||||
pull_request_latest, pull_request_latest)
|
||||
|
||||
c.versions = versions + [latest_ver]
|
||||
.get_pull_request_resolved_todos(pull_request_latest)
|
||||
|
||||
# if we use version, then do not show later comments
|
||||
# than current version
|
||||
|
|
@ -522,8 +551,8 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
# empty version means latest, so we keep this to prevent
|
||||
# double caching
|
||||
version_normalized = version or 'latest'
|
||||
from_version_normalized = from_version or 'latest'
|
||||
version_normalized = version or PullRequest.LATEST_VER
|
||||
from_version_normalized = from_version or PullRequest.LATEST_VER
|
||||
|
||||
cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(target_repo)
|
||||
cache_file_path = diff_cache_exist(
|
||||
|
|
@ -615,7 +644,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
diff_limit, file_limit, c.fulldiff,
|
||||
hide_whitespace_changes, diff_context,
|
||||
use_ancestor=use_ancestor
|
||||
)
|
||||
)
|
||||
|
||||
# save cached diff
|
||||
if caching_enabled:
|
||||
|
|
@ -719,7 +748,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
# current user review statuses for each version
|
||||
c.review_versions = {}
|
||||
if self._rhodecode_user.user_id in allowed_reviewers:
|
||||
if self._rhodecode_user.user_id in c.allowed_reviewers:
|
||||
for co in general_comments:
|
||||
if co.author.user_id == self._rhodecode_user.user_id:
|
||||
status = co.status_change
|
||||
|
|
@ -935,6 +964,83 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
}
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@view_config(
|
||||
route_name='pullrequest_comments', request_method='POST',
|
||||
renderer='string', xhr=True)
|
||||
def pullrequest_comments(self):
|
||||
self.load_default_context()
|
||||
|
||||
pull_request = PullRequest.get_or_404(
|
||||
self.request.matchdict['pull_request_id'])
|
||||
pull_request_id = pull_request.pull_request_id
|
||||
version = self.request.GET.get('version')
|
||||
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/pullrequests/pullrequest_show.mako')
|
||||
c = _render.get_call_context()
|
||||
|
||||
(pull_request_latest,
|
||||
pull_request_at_ver,
|
||||
pull_request_display_obj,
|
||||
at_version) = PullRequestModel().get_pr_version(
|
||||
pull_request_id, version=version)
|
||||
versions = pull_request_display_obj.versions()
|
||||
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
|
||||
c.versions = versions + [latest_ver]
|
||||
|
||||
c.at_version = at_version
|
||||
c.at_version_num = (at_version
|
||||
if at_version and at_version != PullRequest.LATEST_VER
|
||||
else None)
|
||||
|
||||
self.register_comments_vars(c, pull_request_latest, versions)
|
||||
all_comments = c.inline_comments_flat + c.comments
|
||||
return _render('comments_table', all_comments, len(all_comments))
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
'repository.read', 'repository.write', 'repository.admin')
|
||||
@view_config(
|
||||
route_name='pullrequest_todos', request_method='POST',
|
||||
renderer='string', xhr=True)
|
||||
def pullrequest_todos(self):
|
||||
self.load_default_context()
|
||||
|
||||
pull_request = PullRequest.get_or_404(
|
||||
self.request.matchdict['pull_request_id'])
|
||||
pull_request_id = pull_request.pull_request_id
|
||||
version = self.request.GET.get('version')
|
||||
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/pullrequests/pullrequest_show.mako')
|
||||
c = _render.get_call_context()
|
||||
(pull_request_latest,
|
||||
pull_request_at_ver,
|
||||
pull_request_display_obj,
|
||||
at_version) = PullRequestModel().get_pr_version(
|
||||
pull_request_id, version=version)
|
||||
versions = pull_request_display_obj.versions()
|
||||
latest_ver = PullRequest.get_pr_display_object(pull_request_latest, pull_request_latest)
|
||||
c.versions = versions + [latest_ver]
|
||||
|
||||
c.at_version = at_version
|
||||
c.at_version_num = (at_version
|
||||
if at_version and at_version != PullRequest.LATEST_VER
|
||||
else None)
|
||||
|
||||
c.unresolved_comments = CommentsModel() \
|
||||
.get_pull_request_unresolved_todos(pull_request)
|
||||
c.resolved_comments = CommentsModel() \
|
||||
.get_pull_request_resolved_todos(pull_request)
|
||||
|
||||
all_comments = c.unresolved_comments + c.resolved_comments
|
||||
return _render('comments_table', all_comments, len(c.unresolved_comments), todo_comments=True)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@HasRepoPermissionAnyDecorator(
|
||||
|
|
@ -1100,7 +1206,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
self.request.matchdict['pull_request_id'])
|
||||
_ = self.request.translate
|
||||
|
||||
self.load_default_context()
|
||||
c = self.load_default_context()
|
||||
redirect_url = None
|
||||
|
||||
if pull_request.is_closed():
|
||||
|
|
@ -1111,6 +1217,8 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
'redirect_url': redirect_url}
|
||||
|
||||
is_state_changing = pull_request.is_state_changing()
|
||||
c.pr_broadcast_channel = '/repo${}$/pr/{}'.format(
|
||||
pull_request.target_repo.repo_name, pull_request.pull_request_id)
|
||||
|
||||
# only owner or admin can update it
|
||||
allowed_to_update = PullRequestModel().check_user_update(
|
||||
|
|
@ -1134,7 +1242,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
return {'response': True,
|
||||
'redirect_url': redirect_url}
|
||||
|
||||
self._update_commits(pull_request)
|
||||
self._update_commits(c, pull_request)
|
||||
if force_refresh:
|
||||
redirect_url = h.route_path(
|
||||
'pullrequest_show', repo_name=self.db_repo_name,
|
||||
|
|
@ -1170,7 +1278,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
h.flash(msg, category='success')
|
||||
return
|
||||
|
||||
def _update_commits(self, pull_request):
|
||||
def _update_commits(self, c, pull_request):
|
||||
_ = self.request.translate
|
||||
|
||||
with pull_request.set_state(PullRequest.STATE_UPDATING):
|
||||
|
|
@ -1198,13 +1306,18 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
change_source=changed)
|
||||
h.flash(msg, category='success')
|
||||
|
||||
channel = '/repo${}$/pr/{}'.format(
|
||||
pull_request.target_repo.repo_name, pull_request.pull_request_id)
|
||||
message = msg + (
|
||||
' - <a onclick="window.location.reload()">'
|
||||
'<strong>{}</strong></a>'.format(_('Reload page')))
|
||||
|
||||
message_obj = {
|
||||
'message': message,
|
||||
'level': 'success',
|
||||
'topic': '/notifications'
|
||||
}
|
||||
|
||||
channelstream.post_message(
|
||||
channel, message, self._rhodecode_user.username,
|
||||
c.pr_broadcast_channel, message_obj, self._rhodecode_user.username,
|
||||
registry=self.request.registry)
|
||||
else:
|
||||
msg = PullRequestModel.UPDATE_STATUS_MESSAGES[resp.reason]
|
||||
|
|
@ -1474,6 +1587,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
}
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -810,8 +810,7 @@ import tzlocal
|
|||
local_timezone = tzlocal.get_localzone()
|
||||
|
||||
|
||||
def age_component(datetime_iso, value=None, time_is_local=False, tooltip=True):
|
||||
title = value or format_date(datetime_iso)
|
||||
def get_timezone(datetime_iso, time_is_local=False):
|
||||
tzinfo = '+00:00'
|
||||
|
||||
# detect if we have a timezone info, otherwise, add it
|
||||
|
|
@ -822,6 +821,12 @@ def age_component(datetime_iso, value=None, time_is_local=False, tooltip=True):
|
|||
timezone = force_timezone or local_timezone
|
||||
offset = timezone.localize(datetime_iso).strftime('%z')
|
||||
tzinfo = '{}:{}'.format(offset[:-2], offset[-2:])
|
||||
return tzinfo
|
||||
|
||||
|
||||
def age_component(datetime_iso, value=None, time_is_local=False, tooltip=True):
|
||||
title = value or format_date(datetime_iso)
|
||||
tzinfo = get_timezone(datetime_iso, time_is_local=time_is_local)
|
||||
|
||||
return literal(
|
||||
'<time class="timeago {cls}" title="{tt_title}" datetime="{dt}{tzinfo}">{title}</time>'.format(
|
||||
|
|
@ -1650,17 +1655,18 @@ def get_active_pattern_entries(repo_name):
|
|||
|
||||
pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)')
|
||||
|
||||
allowed_link_formats = [
|
||||
'html', 'rst', 'markdown', 'html+hovercard', 'rst+hovercard', 'markdown+hovercard']
|
||||
|
||||
|
||||
def process_patterns(text_string, repo_name, link_format='html', active_entries=None):
|
||||
|
||||
allowed_formats = ['html', 'rst', 'markdown',
|
||||
'html+hovercard', 'rst+hovercard', 'markdown+hovercard']
|
||||
if link_format not in allowed_formats:
|
||||
if link_format not in allowed_link_formats:
|
||||
raise ValueError('Link format can be only one of:{} got {}'.format(
|
||||
allowed_formats, link_format))
|
||||
allowed_link_formats, link_format))
|
||||
|
||||
if active_entries is None:
|
||||
log.debug('Fetch active patterns for repo: %s', repo_name)
|
||||
log.debug('Fetch active issue tracker patterns for repo: %s', repo_name)
|
||||
active_entries = get_active_pattern_entries(repo_name)
|
||||
|
||||
issues_data = []
|
||||
|
|
@ -1718,7 +1724,8 @@ def process_patterns(text_string, repo_name, link_format='html', active_entries=
|
|||
return new_text, issues_data
|
||||
|
||||
|
||||
def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None):
|
||||
def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None,
|
||||
issues_container=None):
|
||||
"""
|
||||
Parses given text message and makes proper links.
|
||||
issues are linked to given issue-server, and rest is a commit link
|
||||
|
|
@ -1741,6 +1748,9 @@ def urlify_commit_message(commit_text, repository=None, active_pattern_entries=N
|
|||
new_text, issues = process_patterns(new_text, repository or '',
|
||||
active_entries=active_pattern_entries)
|
||||
|
||||
if issues_container is not None:
|
||||
issues_container.extend(issues)
|
||||
|
||||
return literal(new_text)
|
||||
|
||||
|
||||
|
|
@ -1781,7 +1791,7 @@ def renderer_from_filename(filename, exclude=None):
|
|||
|
||||
|
||||
def render(source, renderer='rst', mentions=False, relative_urls=None,
|
||||
repo_name=None, active_pattern_entries=None):
|
||||
repo_name=None, active_pattern_entries=None, issues_container=None):
|
||||
|
||||
def maybe_convert_relative_links(html_source):
|
||||
if relative_urls:
|
||||
|
|
@ -1798,6 +1808,8 @@ def render(source, renderer='rst', mentions=False, relative_urls=None,
|
|||
source, issues = process_patterns(
|
||||
source, repo_name, link_format='rst',
|
||||
active_entries=active_pattern_entries)
|
||||
if issues_container is not None:
|
||||
issues_container.extend(issues)
|
||||
|
||||
return literal(
|
||||
'<div class="rst-block">%s</div>' %
|
||||
|
|
@ -1810,6 +1822,8 @@ def render(source, renderer='rst', mentions=False, relative_urls=None,
|
|||
source, issues = process_patterns(
|
||||
source, repo_name, link_format='markdown',
|
||||
active_entries=active_pattern_entries)
|
||||
if issues_container is not None:
|
||||
issues_container.extend(issues)
|
||||
|
||||
return literal(
|
||||
'<div class="markdown-block">%s</div>' %
|
||||
|
|
|
|||
|
|
@ -91,8 +91,7 @@ class CommentsModel(BaseModel):
|
|||
# group by versions, and count until, and display objects
|
||||
|
||||
comment_groups = collections.defaultdict(list)
|
||||
[comment_groups[
|
||||
_co.pull_request_version_id].append(_co) for _co in comments]
|
||||
[comment_groups[_co.pull_request_version_id].append(_co) for _co in comments]
|
||||
|
||||
def yield_comments(pos):
|
||||
for co in comment_groups[pos]:
|
||||
|
|
@ -456,38 +455,54 @@ class CommentsModel(BaseModel):
|
|||
else:
|
||||
action = 'repo.commit.comment.create'
|
||||
|
||||
comment_id = comment.comment_id
|
||||
comment_data = comment.get_api_data()
|
||||
|
||||
self._log_audit_action(
|
||||
action, {'data': comment_data}, auth_user, comment)
|
||||
|
||||
msg_url = ''
|
||||
channel = None
|
||||
if commit_obj:
|
||||
msg_url = commit_comment_url
|
||||
repo_name = repo.repo_name
|
||||
channel = u'/repo${}$/commit/{}'.format(
|
||||
repo_name,
|
||||
commit_obj.raw_id
|
||||
)
|
||||
elif pull_request_obj:
|
||||
msg_url = pr_comment_url
|
||||
repo_name = pr_target_repo.repo_name
|
||||
channel = u'/repo${}$/pr/{}'.format(
|
||||
repo_name,
|
||||
pull_request_id
|
||||
pull_request_obj.pull_request_id
|
||||
)
|
||||
|
||||
message = '<strong>{}</strong> {} - ' \
|
||||
'<a onclick="window.location=\'{}\';' \
|
||||
'window.location.reload()">' \
|
||||
'<strong>{}</strong></a>'
|
||||
message = message.format(
|
||||
user.username, _('made a comment'), msg_url,
|
||||
_('Show it now'))
|
||||
if channel:
|
||||
username = user.username
|
||||
message = '<strong>{}</strong> {} #{}, {}'
|
||||
message = message.format(
|
||||
username,
|
||||
_('posted a new comment'),
|
||||
comment_id,
|
||||
_('Refresh the page to see new comments.'))
|
||||
|
||||
channelstream.post_message(
|
||||
channel, message, user.username,
|
||||
registry=get_current_registry())
|
||||
message_obj = {
|
||||
'message': message,
|
||||
'level': 'success',
|
||||
'topic': '/notifications'
|
||||
}
|
||||
|
||||
channelstream.post_message(
|
||||
channel, message_obj, user.username,
|
||||
registry=get_current_registry())
|
||||
|
||||
message_obj = {
|
||||
'message': None,
|
||||
'user': username,
|
||||
'comment_id': comment_id,
|
||||
'topic': '/comment'
|
||||
}
|
||||
channelstream.post_message(
|
||||
channel, message_obj, user.username,
|
||||
registry=get_current_registry())
|
||||
|
||||
return comment
|
||||
|
||||
|
|
@ -642,15 +657,15 @@ class CommentsModel(BaseModel):
|
|||
return self._group_comments_by_path_and_line_number(q)
|
||||
|
||||
def get_inline_comments_as_list(self, inline_comments, skip_outdated=True,
|
||||
version=None):
|
||||
inline_cnt = 0
|
||||
version=None):
|
||||
inline_comms = []
|
||||
for fname, per_line_comments in inline_comments.iteritems():
|
||||
for lno, comments in per_line_comments.iteritems():
|
||||
for comm in comments:
|
||||
if not comm.outdated_at_version(version) and skip_outdated:
|
||||
inline_cnt += 1
|
||||
inline_comms.append(comm)
|
||||
|
||||
return inline_cnt
|
||||
return inline_comms
|
||||
|
||||
def get_outdated_comments(self, repo_id, pull_request):
|
||||
# TODO: johbo: Remove `repo_id`, it is not needed to find the comments
|
||||
|
|
|
|||
|
|
@ -3821,16 +3821,35 @@ class ChangesetComment(Base, BaseModel):
|
|||
"""
|
||||
Checks if comment is outdated for given pull request version
|
||||
"""
|
||||
return self.outdated and self.pull_request_version_id != version
|
||||
def version_check():
|
||||
return self.pull_request_version_id and self.pull_request_version_id != version
|
||||
|
||||
if self.is_inline:
|
||||
return self.outdated and version_check()
|
||||
else:
|
||||
# general comments don't have .outdated set, also latest don't have a version
|
||||
return version_check()
|
||||
|
||||
def outdated_at_version_js(self, version):
|
||||
"""
|
||||
Checks if comment is outdated for given pull request version
|
||||
"""
|
||||
return json.dumps(self.outdated_at_version(version))
|
||||
|
||||
def older_than_version(self, version):
|
||||
"""
|
||||
Checks if comment is made from previous version than given
|
||||
"""
|
||||
if version is None:
|
||||
return self.pull_request_version_id is not None
|
||||
return self.pull_request_version != version
|
||||
|
||||
return self.pull_request_version_id < version
|
||||
return self.pull_request_version < version
|
||||
|
||||
def older_than_version_js(self, version):
|
||||
"""
|
||||
Checks if comment is made from previous version than given
|
||||
"""
|
||||
return json.dumps(self.older_than_version(version))
|
||||
|
||||
@property
|
||||
def commit_id(self):
|
||||
|
|
@ -4327,6 +4346,7 @@ class PullRequest(Base, _PullRequestBase):
|
|||
__table_args__ = (
|
||||
base_table_args,
|
||||
)
|
||||
LATEST_VER = 'latest'
|
||||
|
||||
pull_request_id = Column(
|
||||
'pull_request_id', Integer(), nullable=False, primary_key=True)
|
||||
|
|
@ -4385,6 +4405,10 @@ class PullRequest(Base, _PullRequestBase):
|
|||
def pull_request_version_id(self):
|
||||
return getattr(pull_request_obj, 'pull_request_version_id', None)
|
||||
|
||||
@property
|
||||
def pull_request_last_version(self):
|
||||
return pull_request_obj.pull_request_last_version
|
||||
|
||||
attrs = StrictAttributeDict(pull_request_obj.get_api_data(with_merge_state=False))
|
||||
|
||||
attrs.author = StrictAttributeDict(
|
||||
|
|
@ -4449,6 +4473,10 @@ class PullRequest(Base, _PullRequestBase):
|
|||
"""
|
||||
return self.versions.count() + 1
|
||||
|
||||
@property
|
||||
def pull_request_last_version(self):
|
||||
return self.versions_count
|
||||
|
||||
|
||||
class PullRequestVersion(Base, _PullRequestBase):
|
||||
__tablename__ = 'pull_request_versions'
|
||||
|
|
|
|||
|
|
@ -240,14 +240,14 @@ div.markdown-block ol {
|
|||
div.markdown-block ul.checkbox li,
|
||||
div.markdown-block ol.checkbox li {
|
||||
list-style: none !important;
|
||||
margin: 6px !important;
|
||||
margin: 0px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
div.markdown-block ul li,
|
||||
div.markdown-block ol li {
|
||||
list-style: disc !important;
|
||||
margin: 6px !important;
|
||||
margin: 0px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1510,18 +1510,14 @@ table.integrations {
|
|||
min-height: 55px;
|
||||
}
|
||||
|
||||
.reviewers_member {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.reviewer_reason {
|
||||
padding-left: 20px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
.reviewer_status {
|
||||
display: inline-block;
|
||||
width: 25px;
|
||||
min-width: 25px;
|
||||
width: 20px;
|
||||
min-width: 20px;
|
||||
height: 1.2em;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
|
@ -1544,23 +1540,17 @@ table.integrations {
|
|||
}
|
||||
|
||||
.reviewer_member_mandatory {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 8px;
|
||||
width: 16px;
|
||||
font-size: 11px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: black;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.reviewer_member_mandatory_remove,
|
||||
.reviewer_member_remove {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 16px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0;
|
||||
color: black;
|
||||
}
|
||||
|
|
@ -1617,7 +1607,8 @@ table.integrations {
|
|||
.td-todo-number {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
width: 15%;
|
||||
width: 1%;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.td-todo-gravatar {
|
||||
|
|
@ -1641,10 +1632,13 @@ table.integrations {
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
table.group_members {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.group_members {
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
list-style: outside none none;
|
||||
|
||||
img {
|
||||
height: @gravatar-size;
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ function registerRCRoutes() {
|
|||
pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
|
||||
pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']);
|
||||
pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
|
||||
pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']);
|
||||
pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']);
|
||||
pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
|
||||
pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
|
||||
pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
|
||||
|
|
|
|||
|
|
@ -28,9 +28,12 @@ export class RhodecodeApp extends PolymerElement {
|
|||
super.connectedCallback();
|
||||
ccLog.debug('rhodeCodeApp created');
|
||||
$.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
|
||||
$.Topic('/comment').subscribe(this.handleComment.bind(this));
|
||||
$.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this));
|
||||
$.Topic('/connection_controller/subscribe').subscribe(
|
||||
this.subscribeToChannelTopic.bind(this));
|
||||
this.subscribeToChannelTopic.bind(this)
|
||||
);
|
||||
|
||||
// this event can be used to coordinate plugins to do their
|
||||
// initialization before channelstream is kicked off
|
||||
$.Topic('/__MAIN_APP__').publish({});
|
||||
|
|
@ -71,6 +74,14 @@ export class RhodecodeApp extends PolymerElement {
|
|||
|
||||
}
|
||||
|
||||
handleComment(data) {
|
||||
if (data.message.comment_id) {
|
||||
if (window.refreshAllComments !== undefined) {
|
||||
refreshAllComments()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
faviconUpdate(data) {
|
||||
this.shadowRoot.querySelector('rhodecode-favicon').counter = data.count;
|
||||
}
|
||||
|
|
@ -95,6 +106,7 @@ export class RhodecodeApp extends PolymerElement {
|
|||
}
|
||||
// append any additional channels registered in other plugins
|
||||
$.Topic('/connection_controller/subscribe').processPrepared();
|
||||
|
||||
channelstreamConnection.connect();
|
||||
}
|
||||
}
|
||||
|
|
@ -157,8 +169,7 @@ export class RhodecodeApp extends PolymerElement {
|
|||
|
||||
handleConnected(event) {
|
||||
var channelstreamConnection = this.getChannelStreamConnection();
|
||||
channelstreamConnection.set('channelsState',
|
||||
event.detail.channels_info);
|
||||
channelstreamConnection.set('channelsState', event.detail.channels_info);
|
||||
channelstreamConnection.set('userState', event.detail.state);
|
||||
channelstreamConnection.set('channels', event.detail.channels);
|
||||
this.propagageChannelsState();
|
||||
|
|
|
|||
|
|
@ -677,7 +677,9 @@ var feedLifetimeOptions = function(query, initialData){
|
|||
query.callback(data);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Retrievew via templateContext.session_attrs.key
|
||||
* */
|
||||
var storeUserSessionAttr = function (key, val) {
|
||||
|
||||
var postData = {
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ var CommentsController = function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
this.showVersion = function (comment_id, comment_history_id) {
|
||||
this.showVersion = function (comment_id, comment_history_id) {
|
||||
|
||||
var historyViewUrl = pyroutes.url(
|
||||
'repo_commit_comment_history_view',
|
||||
|
|
@ -585,7 +585,7 @@ var CommentsController = function() {
|
|||
successRenderCommit,
|
||||
failRenderCommit
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
this.getLineNumber = function(node) {
|
||||
var $node = $(node);
|
||||
|
|
@ -670,8 +670,20 @@ var CommentsController = function() {
|
|||
|
||||
var success = function(response) {
|
||||
$comment.remove();
|
||||
|
||||
if (window.updateSticky !== undefined) {
|
||||
// potentially our comments change the active window size, so we
|
||||
// notify sticky elements
|
||||
updateSticky()
|
||||
}
|
||||
|
||||
if (window.refreshAllComments !== undefined) {
|
||||
// if we have this handler, run it, and refresh all comments boxes
|
||||
refreshAllComments()
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var failure = function(jqXHR, textStatus, errorThrown) {
|
||||
var prefix = "Error while deleting this comment.\n"
|
||||
var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
|
||||
|
|
@ -682,6 +694,9 @@ var CommentsController = function() {
|
|||
return false;
|
||||
};
|
||||
ajaxPOST(url, postData, success, failure);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.deleteComment = function(node) {
|
||||
|
|
@ -727,6 +742,15 @@ var CommentsController = function() {
|
|||
$filediff.find('.hide-line-comments').removeClass('hide-line-comments');
|
||||
$filediff.toggleClass('hide-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()
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -747,7 +771,7 @@ var CommentsController = function() {
|
|||
var cm = commentForm.getCmInstance();
|
||||
|
||||
if (resolvesCommentId){
|
||||
var placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
|
||||
placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
|
|
@ -1077,9 +1101,15 @@ var CommentsController = function() {
|
|||
updateSticky()
|
||||
}
|
||||
|
||||
if (window.refreshAllComments !== undefined) {
|
||||
// if we have this handler, run it, and refresh all comments boxes
|
||||
refreshAllComments()
|
||||
}
|
||||
|
||||
commentForm.setActionButtonsDisabled(false);
|
||||
|
||||
};
|
||||
|
||||
var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
|
||||
var prefix = "Error while editing comment.\n"
|
||||
var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
|
||||
|
|
@ -1209,6 +1239,11 @@ var CommentsController = function() {
|
|||
updateSticky()
|
||||
}
|
||||
|
||||
if (window.refreshAllComments !== undefined) {
|
||||
// if we have this handler, run it, and refresh all comments boxes
|
||||
refreshAllComments()
|
||||
}
|
||||
|
||||
commentForm.setActionButtonsDisabled(false);
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -98,10 +98,13 @@ ReviewersController = function () {
|
|||
var self = this;
|
||||
this.$reviewRulesContainer = $('#review_rules');
|
||||
this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules');
|
||||
this.$userRule = $('.pr-user-rule-container');
|
||||
this.forbidReviewUsers = undefined;
|
||||
this.$reviewMembers = $('#review_members');
|
||||
this.currentRequest = null;
|
||||
this.diffData = null;
|
||||
this.enabledRules = [];
|
||||
|
||||
//dummy handler, we might register our own later
|
||||
this.diffDataHandler = function(data){};
|
||||
|
||||
|
|
@ -116,14 +119,17 @@ ReviewersController = function () {
|
|||
|
||||
this.hideReviewRules = function () {
|
||||
self.$reviewRulesContainer.hide();
|
||||
$(self.$userRule.selector).hide();
|
||||
};
|
||||
|
||||
this.showReviewRules = function () {
|
||||
self.$reviewRulesContainer.show();
|
||||
$(self.$userRule.selector).show();
|
||||
};
|
||||
|
||||
this.addRule = function (ruleText) {
|
||||
self.showReviewRules();
|
||||
self.enabledRules.push(ruleText);
|
||||
return '<div>- {0}</div>'.format(ruleText)
|
||||
};
|
||||
|
||||
|
|
@ -179,6 +185,7 @@ ReviewersController = function () {
|
|||
_gettext('Reviewers picked from source code changes.'))
|
||||
)
|
||||
}
|
||||
|
||||
if (data.rules.forbid_adding_reviewers) {
|
||||
$('#add_reviewer_input').remove();
|
||||
self.$rulesList.append(
|
||||
|
|
@ -186,6 +193,7 @@ ReviewersController = function () {
|
|||
_gettext('Adding new reviewers is forbidden.'))
|
||||
)
|
||||
}
|
||||
|
||||
if (data.rules.forbid_author_to_review) {
|
||||
self.forbidReviewUsers.push(data.rules_data.pr_author);
|
||||
self.$rulesList.append(
|
||||
|
|
@ -193,6 +201,7 @@ ReviewersController = function () {
|
|||
_gettext('Author is not allowed to be a reviewer.'))
|
||||
)
|
||||
}
|
||||
|
||||
if (data.rules.forbid_commit_author_to_review) {
|
||||
|
||||
if (data.rules_data.forbidden_users) {
|
||||
|
|
@ -208,6 +217,12 @@ ReviewersController = function () {
|
|||
)
|
||||
}
|
||||
|
||||
// we don't have any rules set, so we inform users about it
|
||||
if (self.enabledRules.length === 0) {
|
||||
self.addRule(
|
||||
_gettext('No review rules set.'))
|
||||
}
|
||||
|
||||
return self.forbidReviewUsers
|
||||
};
|
||||
|
||||
|
|
@ -347,11 +362,12 @@ ReviewersController = function () {
|
|||
members.innerHTML += renderTemplate('reviewMemberEntry', {
|
||||
'member': reviewer_obj,
|
||||
'mandatory': mandatory,
|
||||
'reasons': reasons,
|
||||
'allowed_to_update': true,
|
||||
'review_status': 'not_reviewed',
|
||||
'review_status_label': _gettext('Not Reviewed'),
|
||||
'reasons': reasons,
|
||||
'create': true
|
||||
'user_group': reviewer_obj.user_group,
|
||||
'create': true,
|
||||
});
|
||||
tooltipActivate();
|
||||
}
|
||||
|
|
@ -600,7 +616,7 @@ VersionController = function () {
|
|||
var $elem = $(elem);
|
||||
var $target = $(target);
|
||||
|
||||
if ($target.is(':visible')) {
|
||||
if ($target.is(':visible') || $target.length === 0) {
|
||||
$target.hide();
|
||||
$elem.html($elem.data('toggleOn'))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@
|
|||
|
||||
<%namespace name="base" file="/base/base.mako"/>
|
||||
<%def name="comment_block(comment, inline=False, active_pattern_entries=None)">
|
||||
<% pr_index_ver = comment.get_index_version(getattr(c, 'versions', [])) %>
|
||||
|
||||
<% comment_ver = comment.get_index_version(getattr(c, 'versions', [])) %>
|
||||
<% latest_ver = len(getattr(c, 'versions', [])) %>
|
||||
|
||||
% if inline:
|
||||
<% outdated_at_ver = comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
|
||||
<% outdated_at_ver = comment.outdated_at_version(c.at_version_num) %>
|
||||
% else:
|
||||
<% outdated_at_ver = comment.older_than_version(getattr(c, 'at_version_num', None)) %>
|
||||
<% outdated_at_ver = comment.older_than_version(c.at_version_num) %>
|
||||
% endif
|
||||
|
||||
<div class="comment
|
||||
|
|
@ -153,38 +155,38 @@
|
|||
</div>
|
||||
%endif
|
||||
|
||||
<a class="permalink" href="#comment-${comment.comment_id}"> ¶</a>
|
||||
<a class="permalink" href="#comment-${comment.comment_id}">¶ #${comment.comment_id}</a>
|
||||
|
||||
<div class="comment-links-block">
|
||||
|
||||
% 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(pr_index_ver, latest_ver)}">
|
||||
outdated ${'v{}'.format(pr_index_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>
|
||||
% elif pr_index_ver:
|
||||
<code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}">
|
||||
${'v{}'.format(pr_index_ver)} |
|
||||
% 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>
|
||||
% endif
|
||||
</a>
|
||||
% else:
|
||||
% if pr_index_ver:
|
||||
% if comment_ver:
|
||||
|
||||
% if comment.outdated:
|
||||
<a class="pr-version"
|
||||
href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}"
|
||||
>
|
||||
${_('Outdated comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}
|
||||
${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}
|
||||
</a> |
|
||||
% else:
|
||||
<a class="tooltip pr-version"
|
||||
title="${_('Comment from pull request version v{0}, latest v{1}').format(pr_index_ver, latest_ver)}"
|
||||
title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}"
|
||||
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)}"
|
||||
>
|
||||
<code class="pr-version-num">
|
||||
${'v{}'.format(pr_index_ver)}
|
||||
${'v{}'.format(comment_ver)}
|
||||
</code>
|
||||
</a> |
|
||||
% endif
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
## to speed up lookups cache some functions before the loop
|
||||
<%
|
||||
active_patterns = h.get_active_pattern_entries(c.repo_name)
|
||||
urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns)
|
||||
urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns, issues_container=getattr(c, 'referenced_commit_issues', None))
|
||||
%>
|
||||
|
||||
%for commit in c.commit_ranges:
|
||||
<tr id="row-${commit.raw_id}"
|
||||
commit_id="${commit.raw_id}"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
<%text>
|
||||
<div style="display: none">
|
||||
|
||||
<script>
|
||||
var CG = new ColorGenerator();
|
||||
</script>
|
||||
|
||||
<script id="ejs_gravatarWithUser" type="text/template" class="ejsTemplate">
|
||||
|
||||
<%
|
||||
|
|
@ -34,10 +38,6 @@ var data_hovercard_url = pyroutes.url('hovercard_user', {"user_id": user_id})
|
|||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var CG = new ColorGenerator();
|
||||
</script>
|
||||
|
||||
<script id="ejs_reviewMemberEntry" type="text/template" class="ejsTemplate">
|
||||
<%
|
||||
if (create) {
|
||||
|
|
@ -47,26 +47,24 @@ var CG = new ColorGenerator();
|
|||
}
|
||||
|
||||
if (member.user_group && member.user_group.vote_rule) {
|
||||
var groupStyle = 'border-right: 2px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule));
|
||||
var reviewGroup = '<i class="icon-user-group"></i>';
|
||||
var reviewGroupColor = CG.asRGB(CG.getColor(member.user_group.vote_rule));
|
||||
} else {
|
||||
var groupStyle = 'border-right: 2px solid transparent';
|
||||
var reviewGroup = null;
|
||||
var reviewGroupColor = 'transparent';
|
||||
}
|
||||
%>
|
||||
|
||||
<li id="reviewer_<%= member.user_id %>" class="reviewer_entry" style="<%= groupStyle%>" tooltip="Review Group">
|
||||
<tr id="reviewer_<%= member.user_id %>" class="reviewer_entry" tooltip="Review Group" data-reviewer-user-id="<%= member.user_id %>">
|
||||
|
||||
<div class="reviewers_member">
|
||||
<td style="width: 20px">
|
||||
<div class="reviewer_status tooltip" title="<%= review_status_label %>">
|
||||
<i class="icon-circle review-status-<%= review_status %>"></i>
|
||||
|
||||
</div>
|
||||
<div id="reviewer_<%= member.user_id %>_name" class="reviewer_name">
|
||||
<% if (mandatory) { %>
|
||||
<div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer">
|
||||
<i class="icon-lock"></i>
|
||||
</div>
|
||||
<% } %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div id="reviewer_<%= member.user_id %>_name" class="reviewer_name">
|
||||
<%-
|
||||
renderTemplate('gravatarWithUser', {
|
||||
'size': 16,
|
||||
|
|
@ -78,12 +76,44 @@ var CG = new ColorGenerator();
|
|||
'gravatar_url': member.gravatar_link
|
||||
})
|
||||
%>
|
||||
<span class="tooltip presence-state" style="display: none" title="This users is currently at this page">
|
||||
<i class="icon-eye" style="color: #0ac878"></i>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td style="width: 10px">
|
||||
<% if (reviewGroup !== null) { %>
|
||||
<span class="tooltip" title="Member of review group from rule: `<%= member.user_group.name %>`" style="color: <%= reviewGroupColor %>">
|
||||
<%- reviewGroup %>
|
||||
</span>
|
||||
<% } %>
|
||||
</td>
|
||||
|
||||
<% if (mandatory) { %>
|
||||
<td style="text-align: right;width: 10px;">
|
||||
<div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer">
|
||||
<i class="icon-lock"></i>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<% } else { %>
|
||||
<td>
|
||||
<% if (allowed_to_update) { %>
|
||||
<div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;">
|
||||
<i class="icon-remove"></i>
|
||||
</div>
|
||||
<% } %>
|
||||
</td>
|
||||
<% } %>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="4" style="display: none" class="pr-user-rule-container">
|
||||
<input type="hidden" name="__start__" value="reviewer:mapping">
|
||||
|
||||
|
||||
<%if (member.user_group && member.user_group.vote_rule) {%>
|
||||
<%if (member.user_group && member.user_group.vote_rule) { %>
|
||||
<div class="reviewer_reason">
|
||||
|
||||
<%if (member.user_group.vote_rule == -1) {%>
|
||||
|
|
@ -92,7 +122,7 @@ var CG = new ColorGenerator();
|
|||
- group votes required: <%= member.user_group.vote_rule %>
|
||||
<%}%>
|
||||
</div>
|
||||
<%}%>
|
||||
<%} %>
|
||||
|
||||
<input type="hidden" name="__start__" value="reasons:sequence">
|
||||
<% for (var i = 0; i < reasons.length; i++) { %>
|
||||
|
|
@ -100,37 +130,24 @@ var CG = new ColorGenerator();
|
|||
<div class="reviewer_reason">- <%= reason %></div>
|
||||
<input type="hidden" name="reason" value="<%= reason %>">
|
||||
<% } %>
|
||||
<input type="hidden" name="__end__" value="reasons:sequence">
|
||||
<input type="hidden" name="__end__" value="reasons:sequence">
|
||||
|
||||
<input type="hidden" name="__start__" value="rules:sequence">
|
||||
<input type="hidden" name="__start__" value="rules:sequence">
|
||||
<% for (var i = 0; i < member.rules.length; i++) { %>
|
||||
<% var rule = member.rules[i] %>
|
||||
<input type="hidden" name="rule_id" value="<%= rule %>">
|
||||
<% } %>
|
||||
<input type="hidden" name="__end__" value="rules:sequence">
|
||||
<input type="hidden" name="__end__" value="rules:sequence">
|
||||
|
||||
<input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" />
|
||||
<input type="hidden" name="mandatory" value="<%= mandatory %>"/>
|
||||
<input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" />
|
||||
<input type="hidden" name="mandatory" value="<%= mandatory %>"/>
|
||||
|
||||
<input type="hidden" name="__end__" value="reviewer:mapping">
|
||||
|
||||
<% if (mandatory) { %>
|
||||
<div class="reviewer_member_mandatory_remove" style="visibility: <%= edit_visibility %>;">
|
||||
<i class="icon-remove"></i>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<% if (allowed_to_update) { %>
|
||||
<div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;">
|
||||
<i class="icon-remove" ></i>
|
||||
</div>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
</li>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script id="ejs_commentVersion" type="text/template" class="ejsTemplate">
|
||||
|
||||
<%
|
||||
|
|
@ -158,7 +175,6 @@ if (show_disabled) {
|
|||
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -360,13 +360,13 @@ ${self.plaintext_footer()}
|
|||
|
||||
div.markdown-block ul.checkbox li, div.markdown-block ol.checkbox li {
|
||||
list-style: none !important;
|
||||
margin: 6px !important;
|
||||
margin: 0px !important;
|
||||
padding: 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block ul li, div.markdown-block ol li {
|
||||
list-style: disc !important;
|
||||
margin: 6px !important;
|
||||
margin: 0px !important;
|
||||
padding: 0 !important
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue