commits/pr pages various fixes.
- added navbar to commit page - improvements on UI - code cleanups
This commit is contained in:
parent
5e1a429afd
commit
f634c67b68
24 changed files with 1513 additions and 1029 deletions
|
|
@ -485,23 +485,10 @@ class TestRepoCommitCommentsView(TestController):
|
|||
|
||||
|
||||
def assert_comment_links(response, comments, inline_comments):
|
||||
if comments == 1:
|
||||
comments_text = "%d General" % comments
|
||||
else:
|
||||
comments_text = "%d General" % comments
|
||||
response.mustcontain(
|
||||
'<span class="display-none" id="general-comments-count">{}</span>'.format(comments))
|
||||
response.mustcontain(
|
||||
'<span class="display-none" id="inline-comments-count">{}</span>'.format(inline_comments))
|
||||
|
||||
if inline_comments == 1:
|
||||
inline_comments_text = "%d Inline" % inline_comments
|
||||
else:
|
||||
inline_comments_text = "%d Inline" % inline_comments
|
||||
|
||||
if comments:
|
||||
response.mustcontain('<a href="#comments">%s</a>,' % comments_text)
|
||||
else:
|
||||
response.mustcontain(comments_text)
|
||||
|
||||
if inline_comments:
|
||||
response.mustcontain(
|
||||
'id="inline-comments-counter">%s' % inline_comments_text)
|
||||
else:
|
||||
response.mustcontain(inline_comments_text)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
|
||||
import logging
|
||||
import collections
|
||||
|
||||
from pyramid.httpexceptions import (
|
||||
HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden, HTTPConflict)
|
||||
|
|
@ -34,14 +34,14 @@ from rhodecode.apps.file_store.exceptions import FileNotAllowedException, FileOv
|
|||
from rhodecode.lib import diffs, codeblocks
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired)
|
||||
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.compat import OrderedDict
|
||||
from rhodecode.lib.diffs import (
|
||||
cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
|
||||
get_diff_whitespace_flag)
|
||||
from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError, CommentVersionMismatch
|
||||
import rhodecode.lib.helpers as h
|
||||
from rhodecode.lib.utils2 import safe_unicode, str2bool
|
||||
from rhodecode.lib.utils2 import safe_unicode, str2bool, StrictAttributeDict
|
||||
from rhodecode.lib.vcs.backends.base import EmptyCommit
|
||||
from rhodecode.lib.vcs.exceptions import (
|
||||
RepositoryError, CommitDoesNotExistError)
|
||||
|
|
@ -87,7 +87,6 @@ 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]
|
||||
|
||||
|
|
@ -116,6 +115,7 @@ class RepoCommitsView(RepoAppView):
|
|||
except Exception:
|
||||
log.exception("General failure")
|
||||
raise HTTPNotFound()
|
||||
single_commit = len(c.commit_ranges) == 1
|
||||
|
||||
c.changes = OrderedDict()
|
||||
c.lines_added = 0
|
||||
|
|
@ -129,23 +129,48 @@ class RepoCommitsView(RepoAppView):
|
|||
c.inline_comments = []
|
||||
c.files = []
|
||||
|
||||
c.statuses = []
|
||||
c.comments = []
|
||||
c.unresolved_comments = []
|
||||
c.resolved_comments = []
|
||||
if len(c.commit_ranges) == 1:
|
||||
|
||||
# Single commit
|
||||
if single_commit:
|
||||
commit = c.commit_ranges[0]
|
||||
c.comments = CommentsModel().get_comments(
|
||||
self.db_repo.repo_id,
|
||||
revision=commit.raw_id)
|
||||
c.statuses.append(ChangesetStatusModel().get_status(
|
||||
self.db_repo.repo_id, commit.raw_id))
|
||||
|
||||
# comments from PR
|
||||
statuses = ChangesetStatusModel().get_statuses(
|
||||
self.db_repo.repo_id, commit.raw_id,
|
||||
with_revisions=True)
|
||||
prs = set(st.pull_request for st in statuses
|
||||
if st.pull_request is not None)
|
||||
|
||||
prs = set()
|
||||
reviewers = list()
|
||||
reviewers_duplicates = set() # to not have duplicates from multiple votes
|
||||
for c_status in statuses:
|
||||
|
||||
# extract associated pull-requests from votes
|
||||
if c_status.pull_request:
|
||||
prs.add(c_status.pull_request)
|
||||
|
||||
# extract reviewers
|
||||
_user_id = c_status.author.user_id
|
||||
if _user_id not in reviewers_duplicates:
|
||||
reviewers.append(
|
||||
StrictAttributeDict({
|
||||
'user': c_status.author,
|
||||
|
||||
# fake attributed for commit, page that we don't have
|
||||
# but we share the display with PR page
|
||||
'mandatory': False,
|
||||
'reasons': [],
|
||||
'rule_user_group_data': lambda: None
|
||||
})
|
||||
)
|
||||
reviewers_duplicates.add(_user_id)
|
||||
|
||||
c.allowed_reviewers = reviewers
|
||||
# from associated statuses, check the pull requests, and
|
||||
# show comments from them
|
||||
for pr in prs:
|
||||
|
|
@ -156,6 +181,37 @@ class RepoCommitsView(RepoAppView):
|
|||
c.resolved_comments = CommentsModel()\
|
||||
.get_commit_resolved_todos(commit.raw_id)
|
||||
|
||||
c.inline_comments_flat = CommentsModel()\
|
||||
.get_commit_inline_comments(commit.raw_id)
|
||||
|
||||
review_statuses = ChangesetStatusModel().aggregate_votes_by_user(
|
||||
statuses, reviewers)
|
||||
|
||||
c.commit_review_status = ChangesetStatus.STATUS_NOT_REVIEWED
|
||||
|
||||
c.commit_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
|
||||
|
||||
for review_obj, member, reasons, mandatory, status in review_statuses:
|
||||
member_reviewer = h.reviewer_as_json(
|
||||
member, reasons=reasons, mandatory=mandatory,
|
||||
user_group=None
|
||||
)
|
||||
|
||||
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'] = False
|
||||
c.commit_set_reviewers_data_json['reviewers'].append(member_reviewer)
|
||||
|
||||
c.commit_set_reviewers_data_json = json.dumps(c.commit_set_reviewers_data_json)
|
||||
|
||||
# NOTE(marcink): this uses the same voting logic as in pull-requests
|
||||
c.commit_review_status = ChangesetStatusModel().calculate_status(review_statuses)
|
||||
c.commit_broadcast_channel = u'/repo${}$/commit/{}'.format(
|
||||
c.repo_name,
|
||||
commit.raw_id
|
||||
)
|
||||
|
||||
diff = None
|
||||
# Iterate over ranges (default commit view is always one commit)
|
||||
for commit in c.commit_ranges:
|
||||
|
|
@ -397,6 +453,7 @@ class RepoCommitsView(RepoAppView):
|
|||
}
|
||||
if comment:
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ from rhodecode.lib.ext_json import json
|
|||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoPermissionAny, HasRepoPermissionAnyDecorator,
|
||||
NotAnonymous, CSRFRequired)
|
||||
from rhodecode.lib.utils2 import str2bool, safe_str, safe_unicode
|
||||
from rhodecode.lib.utils2 import str2bool, safe_str, safe_unicode, safe_int
|
||||
from rhodecode.lib.vcs.backends.base import EmptyCommit, UpdateFailureReason
|
||||
from rhodecode.lib.vcs.exceptions import (
|
||||
CommitDoesNotExistError, RepositoryRequirementError, EmptyRepositoryError)
|
||||
|
|
@ -474,9 +474,6 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
c.pull_request_set_reviewers_data_json = json.dumps(c.pull_request_set_reviewers_data_json)
|
||||
|
||||
|
||||
|
||||
|
||||
general_comments, inline_comments = \
|
||||
self.register_comments_vars(c, pull_request_latest, versions)
|
||||
|
||||
|
|
@ -980,7 +977,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
version = self.request.GET.get('version')
|
||||
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/pullrequests/pullrequest_show.mako')
|
||||
'rhodecode:templates/base/sidebar.mako')
|
||||
c = _render.get_call_context()
|
||||
|
||||
(pull_request_latest,
|
||||
|
|
@ -999,7 +996,11 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
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))
|
||||
|
||||
existing_ids = filter(
|
||||
lambda e: e, map(safe_int, self.request.POST.getall('comments[]')))
|
||||
return _render('comments_table', all_comments, len(all_comments),
|
||||
existing_ids=existing_ids)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
|
|
@ -1017,7 +1018,7 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
version = self.request.GET.get('version')
|
||||
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/pullrequests/pullrequest_show.mako')
|
||||
'rhodecode:templates/base/sidebar.mako')
|
||||
c = _render.get_call_context()
|
||||
(pull_request_latest,
|
||||
pull_request_at_ver,
|
||||
|
|
@ -1039,7 +1040,10 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
.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)
|
||||
existing_ids = filter(
|
||||
lambda e: e, map(safe_int, self.request.POST.getall('comments[]')))
|
||||
return _render('comments_table', all_comments, len(c.unresolved_comments),
|
||||
todo_comments=True, existing_ids=existing_ids)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
|
|
|
|||
|
|
@ -354,34 +354,37 @@ class ChangesetStatusModel(BaseModel):
|
|||
Session().add(new_status)
|
||||
return new_statuses
|
||||
|
||||
def aggregate_votes_by_user(self, commit_statuses, reviewers_data):
|
||||
|
||||
commit_statuses_map = collections.defaultdict(list)
|
||||
for st in commit_statuses:
|
||||
commit_statuses_map[st.author.username] += [st]
|
||||
|
||||
reviewers = []
|
||||
|
||||
def version(commit_status):
|
||||
return commit_status.version
|
||||
|
||||
for obj in reviewers_data:
|
||||
if not obj.user:
|
||||
continue
|
||||
statuses = commit_statuses_map.get(obj.user.username, None)
|
||||
if statuses:
|
||||
status_groups = itertools.groupby(
|
||||
sorted(statuses, key=version), version)
|
||||
statuses = [(x, list(y)[0]) for x, y in status_groups]
|
||||
|
||||
reviewers.append((obj, obj.user, obj.reasons, obj.mandatory, statuses))
|
||||
|
||||
return reviewers
|
||||
|
||||
def reviewers_statuses(self, pull_request):
|
||||
_commit_statuses = self.get_statuses(
|
||||
pull_request.source_repo,
|
||||
pull_request=pull_request,
|
||||
with_revisions=True)
|
||||
|
||||
commit_statuses = collections.defaultdict(list)
|
||||
for st in _commit_statuses:
|
||||
commit_statuses[st.author.username] += [st]
|
||||
|
||||
pull_request_reviewers = []
|
||||
|
||||
def version(commit_status):
|
||||
return commit_status.version
|
||||
|
||||
for obj in pull_request.reviewers:
|
||||
if not obj.user:
|
||||
continue
|
||||
statuses = commit_statuses.get(obj.user.username, None)
|
||||
if statuses:
|
||||
status_groups = itertools.groupby(
|
||||
sorted(statuses, key=version), version)
|
||||
statuses = [(x, list(y)[0]) for x, y in status_groups]
|
||||
|
||||
pull_request_reviewers.append(
|
||||
(obj, obj.user, obj.reasons, obj.mandatory, statuses))
|
||||
|
||||
return pull_request_reviewers
|
||||
return self.aggregate_votes_by_user(_commit_statuses, pull_request.reviewers)
|
||||
|
||||
def calculated_review_status(self, pull_request, reviewers_statuses=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -228,6 +228,14 @@ class CommentsModel(BaseModel):
|
|||
|
||||
return todos
|
||||
|
||||
def get_commit_inline_comments(self, commit_id):
|
||||
inline_comments = Session().query(ChangesetComment) \
|
||||
.filter(ChangesetComment.line_no != None) \
|
||||
.filter(ChangesetComment.f_path != None) \
|
||||
.filter(ChangesetComment.revision == commit_id)
|
||||
inline_comments = inline_comments.all()
|
||||
return inline_comments
|
||||
|
||||
def _log_audit_action(self, action, action_data, auth_user, comment):
|
||||
audit_logger.store(
|
||||
action=action,
|
||||
|
|
|
|||
|
|
@ -55,3 +55,16 @@
|
|||
margin: 0 auto 35px auto;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-text-success {
|
||||
color: @alert1;
|
||||
|
||||
}
|
||||
|
||||
.alert-text-error {
|
||||
color: @alert2;
|
||||
}
|
||||
|
||||
.alert-text-warning {
|
||||
color: @alert3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ input[type="button"] {
|
|||
|
||||
.btn-group-actions {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
z-index: 50;
|
||||
|
||||
&:not(.open) .btn-action-switcher-container {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -1078,10 +1078,16 @@ input.filediff-collapse-state {
|
|||
background: @color5;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&[op="comments"] { /* comments on file */
|
||||
background: @grey4;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&[op="options"] { /* context menu */
|
||||
background: @grey6;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ a { cursor: pointer; }
|
|||
clear: both;
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
float: right !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,11 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.action-link{
|
||||
margin-left: @padding;
|
||||
padding-left: @padding;
|
||||
|
|
@ -482,6 +487,15 @@ ul.auth_plugins {
|
|||
text-align: left;
|
||||
overflow: hidden;
|
||||
white-space: pre-line;
|
||||
padding-top: 5px
|
||||
}
|
||||
|
||||
#add_reviewer {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#add_reviewer_input {
|
||||
padding-top: 10px
|
||||
}
|
||||
|
||||
.pr-details-title-author-pref {
|
||||
|
|
@ -1169,9 +1183,12 @@ label {
|
|||
a {
|
||||
color: @grey5
|
||||
}
|
||||
@media screen and (max-width: 1200px) {
|
||||
|
||||
// 1024px or smaller
|
||||
@media screen and (max-width: 1180px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
img {
|
||||
|
|
@ -1553,6 +1570,7 @@ table.integrations {
|
|||
width: 16px;
|
||||
padding: 0;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.reviewer_member_mandatory_remove {
|
||||
|
|
@ -1682,7 +1700,7 @@ table.group_members {
|
|||
}
|
||||
|
||||
.reviewer_ac .ac-input {
|
||||
width: 92%;
|
||||
width: 100%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
|
@ -2756,7 +2774,7 @@ table.rctable td.td-search-results div {
|
|||
}
|
||||
|
||||
#help_kb .modal-content{
|
||||
max-width: 750px;
|
||||
max-width: 800px;
|
||||
margin: 10% auto;
|
||||
|
||||
table{
|
||||
|
|
@ -3053,4 +3071,141 @@ form.markup-form {
|
|||
|
||||
.pr-hovercard-title {
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-divider {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.details-inline-block {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.details-inline-block summary {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
details:not([open]) > :not(summary) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.details-reset > summary {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.details-reset > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.details-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 185px;
|
||||
list-style: none;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid @grey5;
|
||||
box-shadow: 0 8px 24px rgba(149, 157, 165, .2);
|
||||
left: -150px;
|
||||
text-align: left;
|
||||
z-index: 90;
|
||||
}
|
||||
|
||||
.dropdown-divider {
|
||||
display: block;
|
||||
height: 0;
|
||||
margin: 8px 0;
|
||||
border-top: 1px solid @grey5;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
padding: 4px 8px 4px 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
background: #fafafa;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
border-left: 1px solid @grey5;
|
||||
}
|
||||
|
||||
.right-sidebar.right-sidebar-expanded {
|
||||
width: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.right-sidebar.right-sidebar-collapsed {
|
||||
width: 40px;
|
||||
padding: 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
float: right;
|
||||
will-change: min-height;
|
||||
background: #fafafa;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
margin: 15px 0px 0 0;
|
||||
}
|
||||
|
||||
.sidebar-toggle a {
|
||||
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: 1.2em;
|
||||
font-weight: 700;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.sidebar-element {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.right-sidebar-collapsed-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1.3em;
|
||||
margin: 0 -15px;
|
||||
}
|
||||
|
||||
.right-sidebar-collapsed-state:hover {
|
||||
background-color: @grey5;
|
||||
}
|
||||
|
||||
.old-comments-marker {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.old-comments-marker td {
|
||||
padding-top: 15px;
|
||||
border-bottom: 1px solid @grey5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@ input {
|
|||
|
||||
&.main_filter_input {
|
||||
padding: 5px 10px;
|
||||
min-width: 340px;
|
||||
|
||||
color: @grey7;
|
||||
background: @black;
|
||||
min-height: 18px;
|
||||
|
|
@ -800,11 +800,34 @@ input {
|
|||
color: @grey2 !important;
|
||||
background: white !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
color: @grey2 !important;
|
||||
background: white !important;
|
||||
}
|
||||
|
||||
min-width: 360px;
|
||||
|
||||
@media screen and (max-width: 1600px) {
|
||||
min-width: 300px;
|
||||
}
|
||||
@media screen and (max-width: 1500px) {
|
||||
min-width: 280px;
|
||||
}
|
||||
@media screen and (max-width: 1400px) {
|
||||
min-width: 260px;
|
||||
}
|
||||
@media screen and (max-width: 1300px) {
|
||||
min-width: 240px;
|
||||
}
|
||||
@media screen and (max-width: 1200px) {
|
||||
min-width: 220px;
|
||||
}
|
||||
@media screen and (max-width: 720px) {
|
||||
min-width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@
|
|||
.icon-remove:before { content: '\e810'; } /* '' */
|
||||
.icon-fork:before { content: '\e811'; } /* '' */
|
||||
.icon-more:before { content: '\e812'; } /* '' */
|
||||
.icon-options:before { content: '\e812'; } /* '' */
|
||||
.icon-search:before { content: '\e813'; } /* '' */
|
||||
.icon-scissors:before { content: '\e814'; } /* '' */
|
||||
.icon-download:before { content: '\e815'; } /* '' */
|
||||
|
|
@ -251,6 +252,7 @@
|
|||
// TRANSFORM
|
||||
.icon-merge:before {transform: rotate(180deg);}
|
||||
.icon-wide-mode:before {transform: rotate(90deg);}
|
||||
.icon-options:before {transform: rotate(90deg);}
|
||||
|
||||
// -- END ICON CLASSES -- //
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,11 @@ function setRCMouseBindings(repoName, repoLandingRev) {
|
|||
window.location = pyroutes.url(
|
||||
'edit_repo_perms', {'repo_name': repoName});
|
||||
});
|
||||
Mousetrap.bind(['t s'], function(e) {
|
||||
if (window.toggleSidebar !== undefined) {
|
||||
window.toggleSidebar();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,4 +35,75 @@ var quick_repo_menu = function() {
|
|||
}, function() {
|
||||
hide_quick_repo_menus();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
window.toggleElement = function (elem, target) {
|
||||
var $elem = $(elem);
|
||||
var $target = $(target);
|
||||
|
||||
if ($target.is(':visible') || $target.length === 0) {
|
||||
$target.hide();
|
||||
$elem.html($elem.data('toggleOn'))
|
||||
} else {
|
||||
$target.show();
|
||||
$elem.html($elem.data('toggleOff'))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var marginExpVal = '300' // needs a sync with `.right-sidebar.right-sidebar-expanded` value
|
||||
var marginColVal = '40' // needs a sync with `.right-sidebar.right-sidebar-collapsed` value
|
||||
|
||||
var marginExpanded = {'margin': '0 {0}px 0 0'.format(marginExpVal)};
|
||||
var marginCollapsed = {'margin': '0 {0}px 0 0'.format(marginColVal)};
|
||||
|
||||
var updateStickyHeader = function () {
|
||||
if (window.updateSticky !== undefined) {
|
||||
// potentially our comments change the active window size, so we
|
||||
// notify sticky elements
|
||||
updateSticky()
|
||||
}
|
||||
}
|
||||
|
||||
var expandSidebar = function () {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
$('.outerwrapper').css(marginExpanded);
|
||||
$('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>');
|
||||
$('.right-sidebar-collapsed-state').hide();
|
||||
$('.right-sidebar-expanded-state').show();
|
||||
$('.branding').addClass('display-none');
|
||||
$sideBar.addClass('right-sidebar-expanded')
|
||||
$sideBar.removeClass('right-sidebar-collapsed')
|
||||
}
|
||||
|
||||
var collapseSidebar = function () {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
$('.outerwrapper').css(marginCollapsed);
|
||||
$('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>');
|
||||
$('.right-sidebar-collapsed-state').show();
|
||||
$('.right-sidebar-expanded-state').hide();
|
||||
$('.branding').removeClass('display-none');
|
||||
$sideBar.removeClass('right-sidebar-expanded')
|
||||
$sideBar.addClass('right-sidebar-collapsed')
|
||||
}
|
||||
|
||||
window.toggleSidebar = function () {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
|
||||
if ($sideBar.hasClass('right-sidebar-expanded')) {
|
||||
// expanded -> collapsed transition
|
||||
collapseSidebar();
|
||||
var sidebarState = 'collapsed';
|
||||
|
||||
} else {
|
||||
// collapsed -> expanded
|
||||
expandSidebar();
|
||||
var sidebarState = 'expanded';
|
||||
}
|
||||
|
||||
// update our other sticky header in same context
|
||||
updateStickyHeader();
|
||||
storeUserSessionAttr('rc_user_session_attr.sidebarState', sidebarState);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,8 +279,11 @@ ReviewersController = function () {
|
|||
$('#user').show(); // show user autocomplete after load
|
||||
|
||||
var commitElements = data["diff_info"]['commits'];
|
||||
|
||||
if (commitElements.length === 0) {
|
||||
prButtonLock(true, _gettext('no commits'), 'all');
|
||||
var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
|
||||
_gettext('There are no commits to merge.'));
|
||||
prButtonLock(true, noCommitsMsg, 'all');
|
||||
|
||||
} else {
|
||||
// un-lock PR button, so we cannot send PR before it's calculated
|
||||
|
|
@ -324,7 +327,6 @@ ReviewersController = function () {
|
|||
};
|
||||
|
||||
this.addReviewMember = function (reviewer_obj, reasons, mandatory) {
|
||||
var members = self.$reviewMembers.get(0);
|
||||
var id = reviewer_obj.user_id;
|
||||
var username = reviewer_obj.username;
|
||||
|
||||
|
|
@ -333,10 +335,10 @@ ReviewersController = function () {
|
|||
|
||||
// register IDS to check if we don't have this ID already in
|
||||
var currentIds = [];
|
||||
var _els = self.$reviewMembers.find('li').toArray();
|
||||
for (el in _els) {
|
||||
currentIds.push(_els[el].id)
|
||||
}
|
||||
|
||||
$.each(self.$reviewMembers.find('.reviewer_entry'), function (index, value) {
|
||||
currentIds.push($(value).data('reviewerUserId'))
|
||||
})
|
||||
|
||||
var userAllowedReview = function (userId) {
|
||||
var allowed = true;
|
||||
|
|
@ -354,12 +356,12 @@ ReviewersController = function () {
|
|||
alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
|
||||
} else {
|
||||
// only add if it's not there
|
||||
var alreadyReviewer = currentIds.indexOf('reviewer_' + id) != -1;
|
||||
var alreadyReviewer = currentIds.indexOf(id) != -1;
|
||||
|
||||
if (alreadyReviewer) {
|
||||
alert(_gettext('User `{0}` already in reviewers').format(username));
|
||||
} else {
|
||||
members.innerHTML += renderTemplate('reviewMemberEntry', {
|
||||
var reviewerEntry = renderTemplate('reviewMemberEntry', {
|
||||
'member': reviewer_obj,
|
||||
'mandatory': mandatory,
|
||||
'reasons': reasons,
|
||||
|
|
@ -368,7 +370,9 @@ ReviewersController = function () {
|
|||
'review_status_label': _gettext('Not Reviewed'),
|
||||
'user_group': reviewer_obj.user_group,
|
||||
'create': true,
|
||||
});
|
||||
'rule_show': true,
|
||||
})
|
||||
$(self.$reviewMembers.selector).append(reviewerEntry);
|
||||
tooltipActivate();
|
||||
}
|
||||
}
|
||||
|
|
@ -492,7 +496,7 @@ var ReviewerAutoComplete = function(inputId) {
|
|||
};
|
||||
|
||||
|
||||
VersionController = function () {
|
||||
window.VersionController = function () {
|
||||
var self = this;
|
||||
this.$verSource = $('input[name=ver_source]');
|
||||
this.$verTarget = $('input[name=ver_target]');
|
||||
|
|
@ -612,25 +616,10 @@ VersionController = function () {
|
|||
return false
|
||||
};
|
||||
|
||||
this.toggleElement = function (elem, target) {
|
||||
var $elem = $(elem);
|
||||
var $target = $(target);
|
||||
|
||||
if ($target.is(':visible') || $target.length === 0) {
|
||||
$target.hide();
|
||||
$elem.html($elem.data('toggleOn'))
|
||||
} else {
|
||||
$target.show();
|
||||
$elem.html($elem.data('toggleOff'))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
UpdatePrController = function () {
|
||||
window.UpdatePrController = function () {
|
||||
var self = this;
|
||||
this.$updateCommits = $('#update_commits');
|
||||
this.$updateCommitsSwitcher = $('#update_commits_switcher');
|
||||
|
|
@ -672,4 +661,230 @@ UpdatePrController = function () {
|
|||
templateContext.repo_name,
|
||||
templateContext.pull_request_data.pull_request_id, force);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Reviewer display panel
|
||||
*/
|
||||
window.ReviewersPanel = {
|
||||
editButton: null,
|
||||
closeButton: null,
|
||||
addButton: null,
|
||||
removeButtons: null,
|
||||
reviewRules: null,
|
||||
setReviewers: null,
|
||||
|
||||
setSelectors: function () {
|
||||
var self = this;
|
||||
self.editButton = $('#open_edit_reviewers');
|
||||
self.closeButton =$('#close_edit_reviewers');
|
||||
self.addButton = $('#add_reviewer');
|
||||
self.removeButtons = $('.reviewer_member_remove,.reviewer_member_mandatory_remove');
|
||||
},
|
||||
|
||||
init: function (reviewRules, setReviewers) {
|
||||
var self = this;
|
||||
self.setSelectors();
|
||||
|
||||
this.reviewRules = reviewRules;
|
||||
this.setReviewers = setReviewers;
|
||||
|
||||
this.editButton.on('click', function (e) {
|
||||
self.edit();
|
||||
});
|
||||
this.closeButton.on('click', function (e) {
|
||||
self.close();
|
||||
self.renderReviewers();
|
||||
});
|
||||
|
||||
self.renderReviewers();
|
||||
|
||||
},
|
||||
|
||||
renderReviewers: function () {
|
||||
|
||||
$('#review_members').html('')
|
||||
$.each(this.setReviewers.reviewers, function (key, val) {
|
||||
var member = val;
|
||||
|
||||
var entry = renderTemplate('reviewMemberEntry', {
|
||||
'member': member,
|
||||
'mandatory': member.mandatory,
|
||||
'reasons': member.reasons,
|
||||
'allowed_to_update': member.allowed_to_update,
|
||||
'review_status': member.review_status,
|
||||
'review_status_label': member.review_status_label,
|
||||
'user_group': member.user_group,
|
||||
'create': false
|
||||
});
|
||||
|
||||
$('#review_members').append(entry)
|
||||
});
|
||||
tooltipActivate();
|
||||
|
||||
},
|
||||
|
||||
edit: function (event) {
|
||||
this.editButton.hide();
|
||||
this.closeButton.show();
|
||||
this.addButton.show();
|
||||
$(this.removeButtons.selector).css('visibility', 'visible');
|
||||
// review rules
|
||||
reviewersController.loadReviewRules(this.reviewRules);
|
||||
},
|
||||
|
||||
close: function (event) {
|
||||
this.editButton.show();
|
||||
this.closeButton.hide();
|
||||
this.addButton.hide();
|
||||
$(this.removeButtons.selector).css('visibility', 'hidden');
|
||||
// hide review rules
|
||||
reviewersController.hideReviewRules()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* OnLine presence using channelstream
|
||||
*/
|
||||
window.ReviewerPresenceController = function (channel) {
|
||||
var self = this;
|
||||
this.channel = channel;
|
||||
this.users = {};
|
||||
|
||||
this.storeUsers = function (users) {
|
||||
self.users = {}
|
||||
$.each(users, function (index, value) {
|
||||
var userId = value.state.id;
|
||||
self.users[userId] = value.state;
|
||||
})
|
||||
}
|
||||
|
||||
this.render = function () {
|
||||
$.each($('.reviewer_entry'), function (index, value) {
|
||||
var userData = $(value).data();
|
||||
if (self.users[userData.reviewerUserId] !== undefined) {
|
||||
$(value).find('.presence-state').show();
|
||||
} else {
|
||||
$(value).find('.presence-state').hide();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.handlePresence = function (data) {
|
||||
if (data.type == 'presence' && data.channel === self.channel) {
|
||||
this.storeUsers(data.users);
|
||||
this.render()
|
||||
}
|
||||
};
|
||||
|
||||
this.handleChannelUpdate = function (data) {
|
||||
if (data.channel === this.channel) {
|
||||
this.storeUsers(data.state.users);
|
||||
this.render()
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* subscribe to the current presence */
|
||||
$.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
|
||||
/* subscribe to updates e.g connect/disconnect */
|
||||
$.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
|
||||
|
||||
};
|
||||
|
||||
window.refreshComments = function (version) {
|
||||
version = version || templateContext.pull_request_data.pull_request_version || '';
|
||||
|
||||
// Pull request case
|
||||
if (templateContext.pull_request_data.pull_request_id !== null) {
|
||||
var params = {
|
||||
'pull_request_id': templateContext.pull_request_data.pull_request_id,
|
||||
'repo_name': templateContext.repo_name,
|
||||
'version': version,
|
||||
};
|
||||
var loadUrl = pyroutes.url('pullrequest_comments', params);
|
||||
} // commit case
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
var currentIDs = []
|
||||
$.each($('.comment'), function (idx, element) {
|
||||
currentIDs.push($(element).data('commentId'));
|
||||
});
|
||||
var data = {"comments[]": currentIDs};
|
||||
|
||||
var $targetElem = $('.comments-content-table');
|
||||
$targetElem.css('opacity', 0.3);
|
||||
$targetElem.load(
|
||||
loadUrl, data, function (responseText, textStatus, jqXHR) {
|
||||
if (jqXHR.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
var $counterElem = $('#comments-count');
|
||||
var newCount = $(responseText).data('counter');
|
||||
if (newCount !== undefined) {
|
||||
var callback = function () {
|
||||
$counterElem.animate({'opacity': 1.00}, 200)
|
||||
$counterElem.html(newCount);
|
||||
};
|
||||
$counterElem.animate({'opacity': 0.15}, 200, callback);
|
||||
}
|
||||
|
||||
$targetElem.css('opacity', 1);
|
||||
tooltipActivate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
window.refreshTODOs = function (version) {
|
||||
version = version || templateContext.pull_request_data.pull_request_version || '';
|
||||
// Pull request case
|
||||
if (templateContext.pull_request_data.pull_request_id !== null) {
|
||||
var params = {
|
||||
'pull_request_id': templateContext.pull_request_data.pull_request_id,
|
||||
'repo_name': templateContext.repo_name,
|
||||
'version': version,
|
||||
};
|
||||
var loadUrl = pyroutes.url('pullrequest_comments', params);
|
||||
} // commit case
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
var currentIDs = []
|
||||
$.each($('.comment'), function (idx, element) {
|
||||
currentIDs.push($(element).data('commentId'));
|
||||
});
|
||||
|
||||
var data = {"comments[]": currentIDs};
|
||||
var $targetElem = $('.todos-content-table');
|
||||
$targetElem.css('opacity', 0.3);
|
||||
$targetElem.load(
|
||||
loadUrl, data, function (responseText, textStatus, jqXHR) {
|
||||
if (jqXHR.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
var $counterElem = $('#todos-count')
|
||||
var newCount = $(responseText).data('counter');
|
||||
if (newCount !== undefined) {
|
||||
var callback = function () {
|
||||
$counterElem.animate({'opacity': 1.00}, 200)
|
||||
$counterElem.html(newCount);
|
||||
};
|
||||
$counterElem.animate({'opacity': 0.15}, 200, callback);
|
||||
}
|
||||
|
||||
$targetElem.css('opacity', 1);
|
||||
tooltipActivate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
window.refreshAllComments = function (version) {
|
||||
version = version || templateContext.pull_request_data.pull_request_version || '';
|
||||
|
||||
refreshComments(version);
|
||||
refreshTODOs(version);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -701,9 +701,6 @@
|
|||
notice_messages, notice_level = c.rhodecode_user.get_notice_messages()
|
||||
notice_display = 'none' if len(notice_messages) == 0 else ''
|
||||
%>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<ul id="quick" class="main_nav navigation horizontal-list">
|
||||
## notice box for important system messages
|
||||
|
|
@ -1202,6 +1199,7 @@
|
|||
('g p', 'Goto pull requests page'),
|
||||
('g o', 'Goto repository settings'),
|
||||
('g O', 'Goto repository access permissions settings'),
|
||||
('t s', 'Toggle sidebar on some pages'),
|
||||
]
|
||||
%>
|
||||
%for key, desc in elems:
|
||||
|
|
@ -1221,3 +1219,36 @@
|
|||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
"use sctrict";
|
||||
|
||||
var $sideBar = $('.right-sidebar');
|
||||
var expanded = $sideBar.hasClass('right-sidebar-expanded');
|
||||
var sidebarState = templateContext.session_attrs.sidebarState;
|
||||
var sidebarEnabled = $('aside.right-sidebar').get(0);
|
||||
|
||||
if (sidebarState === 'expanded') {
|
||||
expanded = true
|
||||
} else if (sidebarState === 'collapsed') {
|
||||
expanded = false
|
||||
}
|
||||
if (sidebarEnabled) {
|
||||
// show sidebar since it's hidden on load
|
||||
$('.right-sidebar').show();
|
||||
|
||||
// init based on set initial class, or if defined user session attrs
|
||||
if (expanded) {
|
||||
window.expandSidebar();
|
||||
window.updateStickyHeader();
|
||||
|
||||
} else {
|
||||
window.collapseSidebar();
|
||||
window.updateStickyHeader();
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
</script>
|
||||
|
|
|
|||
134
rhodecode/templates/base/sidebar.mako
Normal file
134
rhodecode/templates/base/sidebar.mako
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
## snippet for sidebar elements
|
||||
## usage:
|
||||
## <%namespace name="sidebar" file="/base/sidebar.mako"/>
|
||||
## ${sidebar.comments_table()}
|
||||
<%namespace name="base" file="/base/base.mako"/>
|
||||
|
||||
<%def name="comments_table(comments, counter_num, todo_comments=False, existing_ids=None, is_pr=True)">
|
||||
<%
|
||||
if todo_comments:
|
||||
cls_ = 'todos-content-table'
|
||||
def sorter(entry):
|
||||
user_id = entry.author.user_id
|
||||
resolved = '1' if entry.resolved else '0'
|
||||
if user_id == c.rhodecode_user.user_id:
|
||||
# own comments first
|
||||
user_id = 0
|
||||
return '{}'.format(str(entry.comment_id).zfill(10000))
|
||||
else:
|
||||
cls_ = 'comments-content-table'
|
||||
def sorter(entry):
|
||||
user_id = entry.author.user_id
|
||||
return '{}'.format(str(entry.comment_id).zfill(10000))
|
||||
|
||||
existing_ids = existing_ids or []
|
||||
|
||||
%>
|
||||
|
||||
<table class="todo-table ${cls_}" data-total-count="${len(comments)}" data-counter="${counter_num}">
|
||||
|
||||
% for loop_obj, comment_obj in h.looper(reversed(sorted(comments, key=sorter))):
|
||||
<%
|
||||
display = ''
|
||||
_cls = ''
|
||||
%>
|
||||
|
||||
<%
|
||||
comment_ver_index = comment_obj.get_index_version(getattr(c, 'versions', []))
|
||||
prev_comment_ver_index = 0
|
||||
if loop_obj.previous:
|
||||
prev_comment_ver_index = loop_obj.previous.get_index_version(getattr(c, 'versions', []))
|
||||
|
||||
ver_info = None
|
||||
if getattr(c, 'versions', []):
|
||||
ver_info = c.versions[comment_ver_index-1] if comment_ver_index else None
|
||||
%>
|
||||
<% hidden_at_ver = comment_obj.outdated_at_version_js(c.at_version_num) %>
|
||||
<% is_from_old_ver = comment_obj.older_than_version_js(c.at_version_num) %>
|
||||
<%
|
||||
if (prev_comment_ver_index > comment_ver_index):
|
||||
comments_ver_divider = comment_ver_index
|
||||
else:
|
||||
comments_ver_divider = None
|
||||
%>
|
||||
|
||||
% if todo_comments:
|
||||
% if comment_obj.resolved:
|
||||
<% _cls = 'resolved-todo' %>
|
||||
<% display = 'none' %>
|
||||
% endif
|
||||
% else:
|
||||
## SKIP TODOs we display them in other area
|
||||
% if comment_obj.is_todo:
|
||||
<% display = 'none' %>
|
||||
% endif
|
||||
## Skip outdated comments
|
||||
% if comment_obj.outdated:
|
||||
<% display = 'none' %>
|
||||
<% _cls = 'hidden-comment' %>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
% if not todo_comments and comments_ver_divider:
|
||||
<tr class="old-comments-marker">
|
||||
<td colspan="3">
|
||||
% if ver_info:
|
||||
<code>v${comments_ver_divider} ${h.age_component(ver_info.created_on, time_is_local=True, tooltip=False)}</code>
|
||||
% else:
|
||||
<code>v${comments_ver_divider}</code>
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
% endif
|
||||
|
||||
<tr class="${_cls}" style="display: ${display};" data-sidebar-comment-id="${comment_obj.comment_id}">
|
||||
<td class="td-todo-number">
|
||||
|
||||
<a class="${('todo-resolved' if comment_obj.resolved else '')} permalink"
|
||||
href="#comment-${comment_obj.comment_id}"
|
||||
onclick="return Rhodecode.comments.scrollToComment($('#comment-${comment_obj.comment_id}'), 0, ${hidden_at_ver})">
|
||||
|
||||
<%
|
||||
version_info = ''
|
||||
if is_pr:
|
||||
version_info = (' made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else ' made in this version')
|
||||
%>
|
||||
|
||||
% if todo_comments:
|
||||
% if comment_obj.is_inline:
|
||||
<i class="tooltip icon-code" title="Inline TODO comment${version_info}."></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="General TODO comment${version_info}."></i>
|
||||
% endif
|
||||
% else:
|
||||
% if comment_obj.outdated:
|
||||
<i class="tooltip icon-comment-toggle" title="Inline Outdated made in v${comment_ver_index}."></i>
|
||||
% elif comment_obj.is_inline:
|
||||
<i class="tooltip icon-code" title="Inline comment${version_info}."></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="General comment${version_info}."></i>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
</a>
|
||||
## NEW, since refresh
|
||||
% if existing_ids and comment_obj.comment_id not in existing_ids:
|
||||
<span class="tag">NEW</span>
|
||||
% endif
|
||||
</td>
|
||||
|
||||
<td class="td-todo-gravatar">
|
||||
${base.gravatar(comment_obj.author.email, 16, user=comment_obj.author, tooltip=True, extra_class=['no-margin'])}
|
||||
</td>
|
||||
<td class="todo-comment-text-wrapper">
|
||||
<div class="tooltip todo-comment-text timeago ${('todo-resolved' if comment_obj.resolved else '')} " title="${h.format_date(comment_obj.created_on)}" datetime="${comment_obj.created_on}${h.get_timezone(comment_obj.created_on, time_is_local=True)}">
|
||||
<code>${h.chop_at_smart(comment_obj.text, '\n', suffix_if_chopped='...')}</code>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
% endfor
|
||||
|
||||
</table>
|
||||
|
||||
</%def>
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
<%namespace name="base" file="/base/base.mako"/>
|
||||
<%namespace name="diff_block" file="/changeset/diff_block.mako"/>
|
||||
<%namespace name="file_base" file="/files/base.mako"/>
|
||||
<%namespace name="sidebar" file="/base/sidebar.mako"/>
|
||||
|
||||
|
||||
<%def name="title()">
|
||||
${_('{} Commit').format(c.repo_name)} - ${h.show_id(c.commit)}
|
||||
|
|
@ -100,22 +102,6 @@
|
|||
% endif
|
||||
</div>
|
||||
|
||||
%if c.statuses:
|
||||
<div class="tag status-tag-${c.statuses[0]} pull-right">
|
||||
<i class="icon-circle review-status-${c.statuses[0]}"></i>
|
||||
<div class="pull-right">${h.commit_status_lbl(c.statuses[0])}</div>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fieldset collapsable-content" data-toggle="summary-details" style="display: none;">
|
||||
<div class="left-label-summary">
|
||||
<p>${_('Commit navigation')}:</p>
|
||||
<div class="right-label-summary">
|
||||
<span id="parent_link" class="tag tagtag">
|
||||
<a href="#parentCommit" title="${_('Parent Commit')}"><i class="icon-left icon-no-margin"></i>${_('parent')}</a>
|
||||
</span>
|
||||
|
|
@ -123,7 +109,9 @@
|
|||
<span id="child_link" class="tag tagtag">
|
||||
<a href="#childCommit" title="${_('Child Commit')}">${_('child')}<i class="icon-right icon-no-margin"></i></a>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -160,7 +148,9 @@
|
|||
<%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
|
||||
${cbdiffs.render_diffset_menu(c.changes[c.commit.raw_id], commit=c.commit)}
|
||||
${cbdiffs.render_diffset(
|
||||
c.changes[c.commit.raw_id], commit=c.commit, use_comments=True,inline_comments=c.inline_comments )}
|
||||
c.changes[c.commit.raw_id], commit=c.commit, use_comments=True,
|
||||
inline_comments=c.inline_comments,
|
||||
show_todos=False)}
|
||||
</div>
|
||||
|
||||
## template for inline comment form
|
||||
|
|
@ -169,7 +159,7 @@
|
|||
## comments heading with count
|
||||
<div class="comments-heading">
|
||||
<i class="icon-comment"></i>
|
||||
${_('Comments')} ${len(c.comments)}
|
||||
${_('General Comments')} ${len(c.comments)}
|
||||
</div>
|
||||
|
||||
## render comments
|
||||
|
|
@ -180,123 +170,262 @@
|
|||
h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
|
||||
</div>
|
||||
|
||||
## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
|
||||
<script type="text/javascript">
|
||||
### NAV SIDEBAR
|
||||
<aside class="right-sidebar right-sidebar-expanded" id="commit-nav-sticky" style="display: none">
|
||||
<div class="sidenav navbar__inner" >
|
||||
## TOGGLE
|
||||
<div class="sidebar-toggle" onclick="toggleSidebar(); return false">
|
||||
<a href="#toggleSidebar" class="grey-link-action">
|
||||
|
||||
$(document).ready(function() {
|
||||
</a>
|
||||
</div>
|
||||
|
||||
var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
|
||||
if($('#trimmed_message_box').height() === boxmax){
|
||||
$('#message_expand').show();
|
||||
}
|
||||
## CONTENT
|
||||
<div class="sidebar-content">
|
||||
|
||||
$('#message_expand').on('click', function(e){
|
||||
$('#trimmed_message_box').css('max-height', 'none');
|
||||
$(this).hide();
|
||||
});
|
||||
## RULES SUMMARY/RULES
|
||||
<div class="sidebar-element clear-both">
|
||||
<% vote_title = _ungettext(
|
||||
'Status calculated based on votes from {} reviewer',
|
||||
'Status calculated based on votes from {} reviewers', len(c.allowed_reviewers)).format(len(c.allowed_reviewers))
|
||||
%>
|
||||
|
||||
$('.show-inline-comments').on('click', function(e){
|
||||
var boxid = $(this).attr('data-comment-id');
|
||||
var button = $(this);
|
||||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${vote_title}">
|
||||
<i class="icon-circle review-status-${c.commit_review_status}"></i>
|
||||
${len(c.allowed_reviewers)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
if(button.hasClass("comments-visible")) {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function(index){
|
||||
$(this).hide();
|
||||
## REVIEWERS
|
||||
<div class="right-sidebar-expanded-state pr-details-title">
|
||||
<span class="tooltip sidebar-heading" title="${vote_title}">
|
||||
<i class="icon-circle review-status-${c.commit_review_status}"></i>
|
||||
${_('Reviewers')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="reviewers" class="right-sidebar-expanded-state pr-details-content reviewers">
|
||||
|
||||
<table id="review_members" class="group_members">
|
||||
## This content is loaded via JS and ReviewersPanel
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
## TODOs
|
||||
<div class="sidebar-element clear-both">
|
||||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="TODOs">
|
||||
<i class="icon-flag-filled"></i>
|
||||
<span id="todos-count">${len(c.unresolved_comments)}</span>
|
||||
</div>
|
||||
|
||||
<div class="right-sidebar-expanded-state pr-details-title">
|
||||
## Only show unresolved, that is only what matters
|
||||
<span class="sidebar-heading noselect" onclick="refreshTODOs(); return false">
|
||||
<i class="icon-flag-filled"></i>
|
||||
TODOs
|
||||
</span>
|
||||
|
||||
% if c.resolved_comments:
|
||||
<span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return toggleElement(this, '.resolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
|
||||
% else:
|
||||
<span class="block-right last-item noselect">Show resolved</span>
|
||||
% endif
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right-sidebar-expanded-state pr-details-content">
|
||||
% if c.unresolved_comments + c.resolved_comments:
|
||||
${sidebar.comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True, is_pr=False)}
|
||||
% else:
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
${_('No TODOs yet')}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## COMMENTS
|
||||
<div class="sidebar-element clear-both">
|
||||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}">
|
||||
<i class="icon-comment" style="color: #949494"></i>
|
||||
<span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span>
|
||||
<span class="display-none" id="general-comments-count">${len(c.comments)}</span>
|
||||
<span class="display-none" id="inline-comments-count">${len(c.inline_comments_flat)}</span>
|
||||
</div>
|
||||
|
||||
<div class="right-sidebar-expanded-state pr-details-title">
|
||||
<span class="sidebar-heading noselect" onclick="refreshComments(); return false">
|
||||
<i class="icon-comment" style="color: #949494"></i>
|
||||
${_('Comments')}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="right-sidebar-expanded-state pr-details-content">
|
||||
% if c.inline_comments_flat + c.comments:
|
||||
${sidebar.comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments), is_pr=False)}
|
||||
% else:
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
${_('No Comments yet')}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
|
||||
<script type="text/javascript">
|
||||
window.setReviewersData = ${c.commit_set_reviewers_data_json | n};
|
||||
|
||||
$(document).ready(function () {
|
||||
var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
|
||||
|
||||
if ($('#trimmed_message_box').height() === boxmax) {
|
||||
$('#message_expand').show();
|
||||
}
|
||||
|
||||
$('#message_expand').on('click', function (e) {
|
||||
$('#trimmed_message_box').css('max-height', 'none');
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
$('.show-inline-comments').on('click', function (e) {
|
||||
var boxid = $(this).attr('data-comment-id');
|
||||
var button = $(this);
|
||||
|
||||
if (button.hasClass("comments-visible")) {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).hide();
|
||||
});
|
||||
button.removeClass("comments-visible");
|
||||
} else {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function(index){
|
||||
$(this).show();
|
||||
} else {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).show();
|
||||
});
|
||||
button.addClass("comments-visible");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// next links
|
||||
$('#child_link').on('click', function(e){
|
||||
// fetch via ajax what is going to be the next link, if we have
|
||||
// >1 links show them to user to choose
|
||||
if(!$('#child_link').hasClass('disabled')){
|
||||
$.ajax({
|
||||
// next links
|
||||
$('#child_link').on('click', function (e) {
|
||||
// fetch via ajax what is going to be the next link, if we have
|
||||
// >1 links show them to user to choose
|
||||
if (!$('#child_link').hasClass('disabled')) {
|
||||
$.ajax({
|
||||
url: '${h.route_path('repo_commit_children',repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
|
||||
success: function(data) {
|
||||
if(data.results.length === 0){
|
||||
$('#child_link').html("${_('No Child Commits')}").addClass('disabled');
|
||||
}
|
||||
if(data.results.length === 1){
|
||||
var commit = data.results[0];
|
||||
window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
|
||||
}
|
||||
else if(data.results.length === 2){
|
||||
$('#child_link').addClass('disabled');
|
||||
$('#child_link').addClass('double');
|
||||
success: function (data) {
|
||||
if (data.results.length === 0) {
|
||||
$('#child_link').html("${_('No Child Commits')}").addClass('disabled');
|
||||
}
|
||||
if (data.results.length === 1) {
|
||||
var commit = data.results[0];
|
||||
window.location = pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': commit.raw_id
|
||||
});
|
||||
} else if (data.results.length === 2) {
|
||||
$('#child_link').addClass('disabled');
|
||||
$('#child_link').addClass('double');
|
||||
|
||||
var _html = '';
|
||||
_html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
|
||||
.replace('__branch__', data.results[0].branch)
|
||||
.replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
|
||||
.replace('__title__', data.results[0].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
|
||||
_html +=' | ';
|
||||
_html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
|
||||
.replace('__branch__', data.results[1].branch)
|
||||
.replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
|
||||
.replace('__title__', data.results[1].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
|
||||
$('#child_link').html(_html);
|
||||
}
|
||||
var _html = '';
|
||||
_html += '<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
|
||||
.replace('__branch__', data.results[0].branch)
|
||||
.replace('__rev__', 'r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0, 6)))
|
||||
.replace('__title__', data.results[0].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': data.results[0].raw_id
|
||||
}));
|
||||
_html += ' | ';
|
||||
_html += '<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a> '
|
||||
.replace('__branch__', data.results[1].branch)
|
||||
.replace('__rev__', 'r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0, 6)))
|
||||
.replace('__title__', data.results[1].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': data.results[1].raw_id
|
||||
}));
|
||||
$('#child_link').html(_html);
|
||||
}
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// prev links
|
||||
$('#parent_link').on('click', function(e){
|
||||
// fetch via ajax what is going to be the next link, if we have
|
||||
// >1 links show them to user to choose
|
||||
if(!$('#parent_link').hasClass('disabled')){
|
||||
$.ajax({
|
||||
// prev links
|
||||
$('#parent_link').on('click', function (e) {
|
||||
// fetch via ajax what is going to be the next link, if we have
|
||||
// >1 links show them to user to choose
|
||||
if (!$('#parent_link').hasClass('disabled')) {
|
||||
$.ajax({
|
||||
url: '${h.route_path("repo_commit_parents",repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
|
||||
success: function(data) {
|
||||
if(data.results.length === 0){
|
||||
$('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
|
||||
}
|
||||
if(data.results.length === 1){
|
||||
var commit = data.results[0];
|
||||
window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
|
||||
}
|
||||
else if(data.results.length === 2){
|
||||
$('#parent_link').addClass('disabled');
|
||||
$('#parent_link').addClass('double');
|
||||
success: function (data) {
|
||||
if (data.results.length === 0) {
|
||||
$('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
|
||||
}
|
||||
if (data.results.length === 1) {
|
||||
var commit = data.results[0];
|
||||
window.location = pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': commit.raw_id
|
||||
});
|
||||
} else if (data.results.length === 2) {
|
||||
$('#parent_link').addClass('disabled');
|
||||
$('#parent_link').addClass('double');
|
||||
|
||||
var _html = '';
|
||||
_html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
|
||||
.replace('__branch__', data.results[0].branch)
|
||||
.replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
|
||||
.replace('__title__', data.results[0].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
|
||||
_html +=' | ';
|
||||
_html +='<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
|
||||
.replace('__branch__', data.results[1].branch)
|
||||
.replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
|
||||
.replace('__title__', data.results[1].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
|
||||
$('#parent_link').html(_html);
|
||||
}
|
||||
var _html = '';
|
||||
_html += '<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
|
||||
.replace('__branch__', data.results[0].branch)
|
||||
.replace('__rev__', 'r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0, 6)))
|
||||
.replace('__title__', data.results[0].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': data.results[0].raw_id
|
||||
}));
|
||||
_html += ' | ';
|
||||
_html += '<a title="__title__" href="__url__"><span class="tag branchtag"><i class="icon-code-fork"></i>__branch__</span> __rev__</a>'
|
||||
.replace('__branch__', data.results[1].branch)
|
||||
.replace('__rev__', 'r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0, 6)))
|
||||
.replace('__title__', data.results[1].message)
|
||||
.replace('__url__', pyroutes.url('repo_commit', {
|
||||
'repo_name': '${c.repo_name}',
|
||||
'commit_id': data.results[1].raw_id
|
||||
}));
|
||||
$('#parent_link').html(_html);
|
||||
}
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// browse tree @ revision
|
||||
$('#files_link').on('click', function(e){
|
||||
window.location = '${h.route_path('repo_files:default_path',repo_name=c.repo_name, commit_id=c.commit.raw_id)}';
|
||||
e.preventDefault();
|
||||
});
|
||||
// browse tree @ revision
|
||||
$('#files_link').on('click', function (e) {
|
||||
window.location = '${h.route_path('repo_files:default_path',repo_name=c.repo_name, commit_id=c.commit.raw_id)}';
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
ReviewersPanel.init(null, setReviewersData);
|
||||
|
||||
var channel = '${c.commit_broadcast_channel}';
|
||||
new ReviewerPresenceController(channel)
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
</%def>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
<%namespace name="base" file="/base/base.mako"/>
|
||||
<%def name="comment_block(comment, inline=False, active_pattern_entries=None)">
|
||||
|
||||
<%
|
||||
from rhodecode.model.comment import CommentsModel
|
||||
comment_model = CommentsModel()
|
||||
%>
|
||||
<% comment_ver = comment.get_index_version(getattr(c, 'versions', [])) %>
|
||||
<% latest_ver = len(getattr(c, 'versions', [])) %>
|
||||
|
||||
|
|
@ -155,20 +159,16 @@
|
|||
</div>
|
||||
%endif
|
||||
|
||||
<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(comment_ver, latest_ver)}">
|
||||
outdated ${'v{}'.format(comment_ver)} |
|
||||
</code>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<code class="action-divider">|</code>
|
||||
% endif
|
||||
</a>
|
||||
% else:
|
||||
|
|
@ -179,45 +179,70 @@
|
|||
href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}"
|
||||
>
|
||||
${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}
|
||||
</a> |
|
||||
</a>
|
||||
<code class="action-divider">|</code>
|
||||
% else:
|
||||
<a class="tooltip pr-version"
|
||||
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(comment_ver)}
|
||||
</code>
|
||||
</a> |
|
||||
<code class="pr-version-num">${'v{}'.format(comment_ver)}</code>
|
||||
</a>
|
||||
<code class="action-divider">|</code>
|
||||
% endif
|
||||
|
||||
% endif
|
||||
% endif
|
||||
|
||||
## show delete comment if it's not a PR (regular comments) or it's PR that is not closed
|
||||
## only super-admin, repo admin OR comment owner can delete, also hide delete if currently viewed comment is outdated
|
||||
%if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
|
||||
## permissions to delete
|
||||
%if 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):
|
||||
<a onclick="return Rhodecode.comments.editComment(this);"
|
||||
class="edit-comment">${_('Edit')}</a>
|
||||
| <a onclick="return Rhodecode.comments.deleteComment(this);"
|
||||
class="delete-comment">${_('Delete')}</a>
|
||||
%else:
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
|
||||
| <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
|
||||
%endif
|
||||
%else:
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
|
||||
| <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
|
||||
%endif
|
||||
<details class="details-reset details-inline-block">
|
||||
<summary class="noselect"><i class="icon-options cursor-pointer"></i></summary>
|
||||
<details-menu class="details-dropdown">
|
||||
|
||||
<div class="dropdown-item">
|
||||
${_('Comment')} #${comment.comment_id}
|
||||
<span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${comment_model.get_url(comment,request, permalink=True, anchor='comment-{}'.format(comment.comment_id))}" title="${_('Copy permalink')}"></span>
|
||||
</div>
|
||||
|
||||
## show delete comment if it's not a PR (regular comments) or it's PR that is not closed
|
||||
## only super-admin, repo admin OR comment owner can delete, also hide delete if currently viewed comment is outdated
|
||||
%if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
|
||||
## permissions to delete
|
||||
%if 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>
|
||||
</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>
|
||||
%else:
|
||||
<div class="dropdown-divider"></div>
|
||||
<div class="dropdown-item">
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
|
||||
</div>
|
||||
%endif
|
||||
%else:
|
||||
<div class="dropdown-divider"></div>
|
||||
<div class="dropdown-item">
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
|
||||
</div>
|
||||
%endif
|
||||
</details-menu>
|
||||
</details>
|
||||
|
||||
<code class="action-divider">|</code>
|
||||
% if outdated_at_ver:
|
||||
| <a onclick="return Rhodecode.comments.prevOutdatedComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous outdated comment')}"> <i class="icon-angle-left"></i> </a>
|
||||
| <a onclick="return Rhodecode.comments.nextOutdatedComment(this);" class="tooltip next-comment" title="${_('Jump to the next outdated comment')}"> <i class="icon-angle-right"></i></a>
|
||||
<a onclick="return Rhodecode.comments.prevOutdatedComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous outdated comment')}"> <i class="icon-angle-left"></i> </a>
|
||||
<a onclick="return Rhodecode.comments.nextOutdatedComment(this);" class="tooltip next-comment" title="${_('Jump to the next outdated comment')}"> <i class="icon-angle-right"></i></a>
|
||||
% else:
|
||||
| <a onclick="return Rhodecode.comments.prevComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous comment')}"> <i class="icon-angle-left"></i></a>
|
||||
| <a onclick="return Rhodecode.comments.nextComment(this);" class="tooltip next-comment" title="${_('Jump to the next comment')}"> <i class="icon-angle-right"></i></a>
|
||||
<a onclick="return Rhodecode.comments.prevComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous comment')}"> <i class="icon-angle-left"></i></a>
|
||||
<a onclick="return Rhodecode.comments.nextComment(this);" class="tooltip next-comment" title="${_('Jump to the next comment')}"> <i class="icon-angle-right"></i></a>
|
||||
% endif
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -102,6 +102,11 @@
|
|||
<%namespace name="diff_block" file="/changeset/diff_block.mako"/>
|
||||
|
||||
%for commit in c.commit_ranges:
|
||||
## commit range header for each individual diff
|
||||
<h3>
|
||||
<a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
|
||||
</h3>
|
||||
|
||||
${cbdiffs.render_diffset_menu(c.changes[commit.raw_id])}
|
||||
${cbdiffs.render_diffset(
|
||||
diffset=c.changes[commit.raw_id],
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
diffset_container_id = h.md5(diffset.target_ref)
|
||||
collapse_all = len(diffset.files) > collapse_when_files_over
|
||||
active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None))
|
||||
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
|
||||
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
|
||||
%>
|
||||
|
||||
%if use_comments:
|
||||
|
|
@ -208,13 +210,6 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
<a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
|
||||
</h2>
|
||||
</div>
|
||||
## commit range header for each individual diff
|
||||
% elif commit and hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1:
|
||||
<div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
|
||||
<div class="clearinner">
|
||||
<a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
<div id="todo-box">
|
||||
|
|
@ -239,6 +234,43 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
<% over_lines_changed_limit = False %>
|
||||
%for i, filediff in enumerate(diffset.files):
|
||||
|
||||
%if filediff.source_file_path and filediff.target_file_path:
|
||||
%if filediff.source_file_path != filediff.target_file_path:
|
||||
## file was renamed, or copied
|
||||
%if RENAMED_FILENODE in filediff.patch['stats']['ops']:
|
||||
<%
|
||||
final_file_name = h.literal(u'{} <i class="icon-angle-left"></i> <del>{}</del>'.format(filediff.target_file_path, filediff.source_file_path))
|
||||
final_path = filediff.target_file_path
|
||||
%>
|
||||
%elif COPIED_FILENODE in filediff.patch['stats']['ops']:
|
||||
<%
|
||||
final_file_name = h.literal(u'{} <i class="icon-angle-left"></i> {}'.format(filediff.target_file_path, filediff.source_file_path))
|
||||
final_path = filediff.target_file_path
|
||||
%>
|
||||
%endif
|
||||
%else:
|
||||
## file was modified
|
||||
<%
|
||||
final_file_name = filediff.source_file_path
|
||||
final_path = final_file_name
|
||||
%>
|
||||
%endif
|
||||
%else:
|
||||
%if filediff.source_file_path:
|
||||
## file was deleted
|
||||
<%
|
||||
final_file_name = filediff.source_file_path
|
||||
final_path = final_file_name
|
||||
%>
|
||||
%else:
|
||||
## file was added
|
||||
<%
|
||||
final_file_name = filediff.target_file_path
|
||||
final_path = final_file_name
|
||||
%>
|
||||
%endif
|
||||
%endif
|
||||
|
||||
<%
|
||||
lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted']
|
||||
over_lines_changed_limit = lines_changed > lines_changed_limit
|
||||
|
|
@ -258,13 +290,39 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
total_file_comments = [_c for _c in h.itertools.chain.from_iterable(file_comments) if not _c.outdated]
|
||||
%>
|
||||
<div class="filediff-collapse-indicator icon-"></div>
|
||||
<span class="pill-group pull-right" >
|
||||
<span class="pill" op="comments">
|
||||
|
||||
## Comments/Options PILL
|
||||
<span class="pill-group pull-right">
|
||||
<span class="pill" op="comments">
|
||||
<i class="icon-comment"></i> ${len(total_file_comments)}
|
||||
</span>
|
||||
|
||||
<details class="details-reset details-inline-block">
|
||||
<summary class="noselect">
|
||||
<i class="pill icon-options cursor-pointer" op="options"></i>
|
||||
</summary>
|
||||
<details-menu class="details-dropdown">
|
||||
|
||||
<div class="dropdown-item">
|
||||
<span>${final_path}</span>
|
||||
<span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="Copy file path"></span>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<div class="dropdown-item">
|
||||
<% permalink = request.current_route_url(_anchor='a_{}'.format(h.FID(filediff.raw_id, filediff.patch['filename']))) %>
|
||||
<a href="${permalink}">¶ permalink</a>
|
||||
<span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${permalink}" title="Copy permalink"></span>
|
||||
</div>
|
||||
|
||||
|
||||
</details-menu>
|
||||
</details>
|
||||
|
||||
</span>
|
||||
${diff_ops(filediff)}
|
||||
|
||||
${diff_ops(final_file_name, filediff)}
|
||||
|
||||
</label>
|
||||
|
||||
|
|
@ -463,43 +521,15 @@ return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
|
|||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="diff_ops(filediff)">
|
||||
<%
|
||||
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
|
||||
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
|
||||
%>
|
||||
<%def name="diff_ops(file_name, filediff)">
|
||||
<%
|
||||
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
|
||||
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
|
||||
%>
|
||||
<span class="pill">
|
||||
<i class="icon-file-text"></i>
|
||||
%if filediff.source_file_path and filediff.target_file_path:
|
||||
%if filediff.source_file_path != filediff.target_file_path:
|
||||
## file was renamed, or copied
|
||||
%if RENAMED_FILENODE in filediff.patch['stats']['ops']:
|
||||
${filediff.target_file_path} ⬅ <del>${filediff.source_file_path}</del>
|
||||
<% final_path = filediff.target_file_path %>
|
||||
%elif COPIED_FILENODE in filediff.patch['stats']['ops']:
|
||||
${filediff.target_file_path} ⬅ ${filediff.source_file_path}
|
||||
<% final_path = filediff.target_file_path %>
|
||||
%endif
|
||||
%else:
|
||||
## file was modified
|
||||
${filediff.source_file_path}
|
||||
<% final_path = filediff.source_file_path %>
|
||||
%endif
|
||||
%else:
|
||||
%if filediff.source_file_path:
|
||||
## file was deleted
|
||||
${filediff.source_file_path}
|
||||
<% final_path = filediff.source_file_path %>
|
||||
%else:
|
||||
## file was added
|
||||
${filediff.target_file_path}
|
||||
<% final_path = filediff.target_file_path %>
|
||||
%endif
|
||||
%endif
|
||||
<i style="color: #aaa" class="on-hover-icon icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy file path')}" onclick="return false;"></i>
|
||||
${file_name}
|
||||
</span>
|
||||
## anchor link
|
||||
<a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}">¶</a>
|
||||
|
||||
<span class="pill-group pull-right">
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,14 @@ var data_hovercard_url = pyroutes.url('hovercard_user', {"user_id": user_id})
|
|||
var reviewGroup = null;
|
||||
var reviewGroupColor = 'transparent';
|
||||
}
|
||||
var rule_show = rule_show || false;
|
||||
|
||||
if (rule_show) {
|
||||
var rule_visibility = 'table-cell';
|
||||
} else {
|
||||
var rule_visibility = 'none';
|
||||
}
|
||||
|
||||
%>
|
||||
|
||||
<tr id="reviewer_<%= member.user_id %>" class="reviewer_entry" tooltip="Review Group" data-reviewer-user-id="<%= member.user_id %>">
|
||||
|
|
@ -98,9 +106,9 @@ var data_hovercard_url = pyroutes.url('hovercard_user', {"user_id": user_id})
|
|||
</td>
|
||||
|
||||
<% } else { %>
|
||||
<td>
|
||||
<td style="text-align: right;width: 10px;">
|
||||
<% if (allowed_to_update) { %>
|
||||
<div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;">
|
||||
<div class="reviewer_member_remove" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;">
|
||||
<i class="icon-remove"></i>
|
||||
</div>
|
||||
<% } %>
|
||||
|
|
@ -110,7 +118,7 @@ var data_hovercard_url = pyroutes.url('hovercard_user', {"user_id": user_id})
|
|||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="4" style="display: none" class="pr-user-rule-container">
|
||||
<td colspan="4" style="display: <%= rule_visibility %>" class="pr-user-rule-container">
|
||||
<input type="hidden" name="__start__" value="reviewer:mapping">
|
||||
|
||||
<%if (member.user_group && member.user_group.vote_rule) { %>
|
||||
|
|
|
|||
|
|
@ -19,21 +19,74 @@
|
|||
<div class="box">
|
||||
${h.secure_form(h.route_path('pullrequest_create', repo_name=c.repo_name, _query=request.GET.mixed()), id='pull_request_form', request=request)}
|
||||
|
||||
<div class="box pr-summary">
|
||||
<div class="box">
|
||||
|
||||
<div class="summary-details block-left">
|
||||
|
||||
|
||||
<div class="pr-details-title">
|
||||
${_('New pull request')}
|
||||
</div>
|
||||
|
||||
<div class="form" style="padding-top: 10px">
|
||||
<!-- fields -->
|
||||
|
||||
<div class="fields" >
|
||||
|
||||
<div class="field">
|
||||
## COMMIT FLOW
|
||||
<div class="field">
|
||||
<div class="label label-textarea">
|
||||
<label for="commit_flow">${_('Commit flow')}:</label>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="flex-container">
|
||||
<div style="width: 45%;">
|
||||
<div class="panel panel-default source-panel">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('Source repository')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div style="display:none">${c.rhodecode_db_repo.description}</div>
|
||||
${h.hidden('source_repo')}
|
||||
${h.hidden('source_ref')}
|
||||
|
||||
<div id="pr_open_message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width: 90px; text-align: center; padding-top: 30px">
|
||||
<div>
|
||||
<i class="icon-right" style="font-size: 2.2em"></i>
|
||||
</div>
|
||||
<div style="position: relative; top: 10px">
|
||||
<span class="tag tag">
|
||||
<span id="switch_base"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="width: 45%;">
|
||||
|
||||
<div class="panel panel-default target-panel">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('Target repository')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div style="display:none" id="target_repo_desc"></div>
|
||||
${h.hidden('target_repo')}
|
||||
${h.hidden('target_ref')}
|
||||
<span id="target_ref_loading" style="display: none">
|
||||
${_('Loading refs...')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
## TITLE
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
<label for="pullrequest_title">${_('Title')}:</label>
|
||||
</div>
|
||||
|
|
@ -43,8 +96,9 @@
|
|||
<p class="help-block">
|
||||
Start the title with WIP: to prevent accidental merge of Work In Progress pull request before it's ready.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## DESC
|
||||
<div class="field">
|
||||
<div class="label label-textarea">
|
||||
<label for="pullrequest_desc">${_('Description')}:</label>
|
||||
|
|
@ -55,39 +109,49 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
## REVIEWERS
|
||||
<div class="field">
|
||||
<div class="label label-textarea">
|
||||
<label for="commit_flow">${_('Commit flow')}:</label>
|
||||
</div>
|
||||
|
||||
## TODO: johbo: Abusing the "content" class here to get the
|
||||
## desired effect. Should be replaced by a proper solution.
|
||||
|
||||
##ORG
|
||||
<div class="content">
|
||||
<strong>${_('Source repository')}:</strong>
|
||||
${c.rhodecode_db_repo.description}
|
||||
<label for="pullrequest_reviewers">${_('Reviewers')}:</label>
|
||||
</div>
|
||||
<div class="content">
|
||||
${h.hidden('source_repo')}
|
||||
${h.hidden('source_ref')}
|
||||
</div>
|
||||
## REVIEW RULES
|
||||
<div id="review_rules" style="display: none" class="reviewers-title">
|
||||
<div class="pr-details-title">
|
||||
${_('Reviewer rules')}
|
||||
</div>
|
||||
<div class="pr-reviewer-rules">
|
||||
## review rules will be appended here, by default reviewers logic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
##OTHER, most Probably the PARENT OF THIS FORK
|
||||
<div class="content">
|
||||
## filled with JS
|
||||
<div id="target_repo_desc"></div>
|
||||
</div>
|
||||
## REVIEWERS
|
||||
<div class="reviewers-title">
|
||||
<div class="pr-details-title">
|
||||
${_('Pull request reviewers')}
|
||||
<span class="calculate-reviewers"> - ${_('loading...')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="reviewers" class="pr-details-content reviewers">
|
||||
## members goes here, filled via JS based on initial selection !
|
||||
<input type="hidden" name="__start__" value="review_members:sequence">
|
||||
<table id="review_members" class="group_members">
|
||||
## This content is loaded via JS and ReviewersPanel
|
||||
</table>
|
||||
<input type="hidden" name="__end__" value="review_members:sequence">
|
||||
|
||||
<div class="content">
|
||||
${h.hidden('target_repo')}
|
||||
${h.hidden('target_ref')}
|
||||
<span id="target_ref_loading" style="display: none">
|
||||
${_('Loading refs...')}
|
||||
</span>
|
||||
<div id="add_reviewer_input" class='ac'>
|
||||
<div class="reviewer_ac">
|
||||
${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
|
||||
<div id="reviewers_container"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## SUBMIT
|
||||
<div class="field">
|
||||
<div class="label label-textarea">
|
||||
<label for="pullrequest_submit"></label>
|
||||
|
|
@ -96,66 +160,14 @@
|
|||
<div class="pr-submit-button">
|
||||
<input id="pr_submit" class="btn" name="save" type="submit" value="${_('Submit Pull Request')}">
|
||||
</div>
|
||||
<div id="pr_open_message"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pr-spacing-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
## AUTHOR
|
||||
<div class="reviewers-title block-right">
|
||||
<div class="pr-details-title">
|
||||
${_('Author of this pull request')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="block-right pr-details-content reviewers">
|
||||
<ul class="group_members">
|
||||
<li>
|
||||
${self.gravatar_with_user(c.rhodecode_user.email, 16, tooltip=True)}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
## REVIEW RULES
|
||||
<div id="review_rules" style="display: none" class="reviewers-title block-right">
|
||||
<div class="pr-details-title">
|
||||
${_('Reviewer rules')}
|
||||
</div>
|
||||
<div class="pr-reviewer-rules">
|
||||
## review rules will be appended here, by default reviewers logic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## REVIEWERS
|
||||
<div class="reviewers-title block-right">
|
||||
<div class="pr-details-title">
|
||||
${_('Pull request reviewers')}
|
||||
<span class="calculate-reviewers"> - ${_('loading...')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="reviewers" class="block-right pr-details-content reviewers">
|
||||
## members goes here, filled via JS based on initial selection !
|
||||
<input type="hidden" name="__start__" value="review_members:sequence">
|
||||
<ul id="review_members" class="group_members"></ul>
|
||||
<input type="hidden" name="__end__" value="review_members:sequence">
|
||||
<div id="add_reviewer_input" class='ac'>
|
||||
<div class="reviewer_ac">
|
||||
${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
|
||||
<div id="reviewers_container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div>
|
||||
## overview pulled by ajax
|
||||
<div id="pull_request_overview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${h.end_form()}
|
||||
</div>
|
||||
|
||||
|
|
@ -243,8 +255,6 @@
|
|||
|
||||
var diffDataHandler = function(data) {
|
||||
|
||||
$('#pull_request_overview').html(data);
|
||||
|
||||
var commitElements = data['commits'];
|
||||
var files = data['files'];
|
||||
var added = data['stats'][0]
|
||||
|
|
@ -303,27 +313,33 @@
|
|||
|
||||
msg += '<input type="hidden" name="__end__" value="revisions:sequence">'
|
||||
msg += _ngettext(
|
||||
'This pull requests will consist of <strong>{0} commit</strong>.',
|
||||
'This pull requests will consist of <strong>{0} commits</strong>.',
|
||||
'Compare summary: <strong>{0} commit</strong>',
|
||||
'Compare summary: <strong>{0} commits</strong>',
|
||||
commitElements.length).format(commitElements.length)
|
||||
|
||||
msg += '\n';
|
||||
msg += '';
|
||||
msg += _ngettext(
|
||||
'<strong>{0} file</strong> changed, ',
|
||||
'<strong>{0} files</strong> changed, ',
|
||||
'<strong>, and {0} file</strong> changed.',
|
||||
'<strong>, and {0} files</strong> changed.',
|
||||
files.length).format(files.length)
|
||||
msg += '<span class="op-added">{0} lines inserted</span>, <span class="op-deleted">{1} lines deleted</span>.'.format(added, deleted)
|
||||
|
||||
msg += '\n\n <a class="" id="pull_request_overview_url" href="{0}" target="_blank">${_('Show detailed compare.')}</a>'.format(url);
|
||||
msg += '\n Diff: <span class="op-added">{0} lines inserted</span>, <span class="op-deleted">{1} lines deleted </span>.'.format(added, deleted)
|
||||
|
||||
msg += '\n <a class="" id="pull_request_overview_url" href="{0}" target="_blank">${_('Show detailed compare.')}</a>'.format(url);
|
||||
|
||||
if (commitElements.length) {
|
||||
var commitsLink = '<a href="#pull_request_overview"><strong>{0}</strong></a>'.format(commitElements.length);
|
||||
prButtonLock(false, msg.replace('__COMMITS__', commitsLink), 'compare');
|
||||
}
|
||||
else {
|
||||
prButtonLock(true, "${_('There are no commits to merge.')}", 'compare');
|
||||
var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
|
||||
_gettext('There are no commits to merge.'));
|
||||
prButtonLock(true, noCommitsMsg, 'compare');
|
||||
}
|
||||
|
||||
//make both panels equal
|
||||
$('.target-panel').height($('.source-panel').height())
|
||||
|
||||
};
|
||||
|
||||
reviewersController = new ReviewersController();
|
||||
|
|
@ -429,10 +445,12 @@
|
|||
|
||||
var targetRepoChanged = function(repoData) {
|
||||
// generate new DESC of target repo displayed next to select
|
||||
|
||||
$('#target_repo_desc').html(repoData['description']);
|
||||
|
||||
var prLink = pyroutes.url('pullrequest_new', {'repo_name': repoData['name']});
|
||||
$('#target_repo_desc').html(
|
||||
"<strong>${_('Target repository')}</strong>: {0}. <a href=\"{1}\">Switch base, and use as source.</a>".format(repoData['description'], prLink)
|
||||
);
|
||||
var title = _gettext('Switch target repository with the source.')
|
||||
$('#switch_base').html("<a class=\"tooltip\" title=\"{0}\" href=\"{1}\">Switch sides</a>".format(title, prLink))
|
||||
|
||||
// generate dynamic select2 for refs.
|
||||
initTargetRefs(repoData['refs']['select2_refs'],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<%inherit file="/base/base.mako"/>
|
||||
<%namespace name="base" file="/base/base.mako"/>
|
||||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||||
<%namespace name="sidebar" file="/base/sidebar.mako"/>
|
||||
|
||||
|
||||
<%def name="title()">
|
||||
${_('{} Pull Request !{}').format(c.repo_name, c.pull_request.pull_request_id)}
|
||||
|
|
@ -21,113 +23,6 @@
|
|||
${self.repo_menu(active='showpullrequest')}
|
||||
</%def>
|
||||
|
||||
<%def name="comments_table(comments, counter_num, todo_comments=False)">
|
||||
<%
|
||||
old_comments = False
|
||||
if todo_comments:
|
||||
cls_ = 'todos-content-table'
|
||||
def sorter(entry):
|
||||
user_id = entry.author.user_id
|
||||
resolved = '1' if entry.resolved else '0'
|
||||
if user_id == c.rhodecode_user.user_id:
|
||||
# own comments first
|
||||
user_id = 0
|
||||
return '{}'.format(str(entry.comment_id).zfill(10000))
|
||||
else:
|
||||
cls_ = 'comments-content-table'
|
||||
def sorter(entry):
|
||||
user_id = entry.author.user_id
|
||||
return '{}'.format(str(entry.comment_id).zfill(10000))
|
||||
|
||||
|
||||
|
||||
%>
|
||||
<table class="todo-table ${cls_}" data-total-count="${len(comments)}" data-counter="${counter_num}">
|
||||
|
||||
% for loop_obj, comment_obj in h.looper(reversed(sorted(comments, key=sorter))):
|
||||
<%
|
||||
display = ''
|
||||
_cls = ''
|
||||
%>
|
||||
<% comment_ver_index = comment_obj.get_index_version(getattr(c, 'versions', [])) %>
|
||||
<%
|
||||
prev_comment_ver_index = 0
|
||||
if loop_obj.previous:
|
||||
prev_comment_ver_index = loop_obj.previous.get_index_version(getattr(c, 'versions', []))
|
||||
%>
|
||||
<% hidden_at_ver = comment_obj.outdated_at_version_js(c.at_version_num) %>
|
||||
<% is_from_old_ver = comment_obj.older_than_version_js(c.at_version_num) %>
|
||||
<%
|
||||
if (prev_comment_ver_index > comment_ver_index) and old_comments is False:
|
||||
old_comments = True
|
||||
%>
|
||||
% if todo_comments:
|
||||
% if comment_obj.resolved:
|
||||
<% _cls = 'resolved-todo' %>
|
||||
<% display = 'none' %>
|
||||
% endif
|
||||
% else:
|
||||
## SKIP TODOs we display them in other area
|
||||
% if comment_obj.is_todo:
|
||||
<% display = 'none' %>
|
||||
% endif
|
||||
## Skip outdated comments
|
||||
% if comment_obj.outdated:
|
||||
<% display = 'none' %>
|
||||
<% _cls = 'hidden-comment' %>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
% if not todo_comments and old_comments:
|
||||
<tr class="old-comments-marker">
|
||||
<td colspan="3"> <code>comments from older versions</code> </td>
|
||||
</tr>
|
||||
## reset markers so we only show this marker once
|
||||
<% old_comments = None %>
|
||||
% endif
|
||||
|
||||
<tr class="${_cls}" style="display: ${display};">
|
||||
<td class="td-todo-number">
|
||||
|
||||
<a class="${('todo-resolved' if comment_obj.resolved else '')} permalink"
|
||||
href="#comment-${comment_obj.comment_id}"
|
||||
onclick="return Rhodecode.comments.scrollToComment($('#comment-${comment_obj.comment_id}'), 0, ${hidden_at_ver})">
|
||||
|
||||
% if todo_comments:
|
||||
% if comment_obj.is_inline:
|
||||
<i class="tooltip icon-code" title="Inline TODO comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="General TODO comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i>
|
||||
% endif
|
||||
% else:
|
||||
% if comment_obj.outdated:
|
||||
<i class="tooltip icon-comment-toggle" title="Inline Outdated made in v${comment_ver_index}."></i>
|
||||
% elif comment_obj.is_inline:
|
||||
<i class="tooltip icon-code" title="Inline comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i>
|
||||
% else:
|
||||
<i class="tooltip icon-comment" title="General comment ${('made in older version (v{})'.format(comment_ver_index) if is_from_old_ver == 'true' else 'made in this version')}."></i>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
#${comment_obj.comment_id}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td class="td-todo-gravatar">
|
||||
${base.gravatar(comment_obj.author.email, 16, user=comment_obj.author, tooltip=True, extra_class=['no-margin'])}
|
||||
</td>
|
||||
<td class="todo-comment-text-wrapper">
|
||||
<div class="tooltip todo-comment-text timeago" title="${h.format_date(comment_obj.created_on)}" datetime="${comment_obj.created_on}${h.get_timezone(comment_obj.created_on, time_is_local=True)}">
|
||||
<code>${h.chop_at_smart(comment_obj.text, '\n', suffix_if_chopped='...')}</code>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
% endfor
|
||||
|
||||
</table>
|
||||
|
||||
</%def>
|
||||
|
||||
|
||||
<%def name="main()">
|
||||
## Container to gather extracted Tickets
|
||||
|
|
@ -140,6 +35,7 @@
|
|||
// TODO: marcink switch this to pyroutes
|
||||
AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
|
||||
templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
|
||||
templateContext.pull_request_data.pull_request_version = '${request.GET.get('version', '')}';
|
||||
</script>
|
||||
|
||||
<div class="box">
|
||||
|
|
@ -226,7 +122,7 @@
|
|||
|
||||
${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.repo_name}</a>
|
||||
|
||||
<a class="source-details-action" href="#expand-source-details" onclick="return versionController.toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
|
||||
<a class="source-details-action" href="#expand-source-details" onclick="return toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
|
||||
<i class="icon-angle-down">more details</i>
|
||||
</a>
|
||||
|
||||
|
|
@ -643,101 +539,12 @@
|
|||
</div>
|
||||
|
||||
|
||||
### NAVBOG RIGHT
|
||||
<style>
|
||||
|
||||
.right-sidebar {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
background: #fafafa;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
border-left: 1px solid #dbdbdb;
|
||||
}
|
||||
|
||||
.right-sidebar.right-sidebar-expanded {
|
||||
width: 320px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.right-sidebar.right-sidebar-collapsed {
|
||||
width: 50px;
|
||||
padding: 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
float: right;
|
||||
will-change: min-height;
|
||||
background: #fafafa;
|
||||
width: 100%;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
margin: 15px 0px 0 0;
|
||||
}
|
||||
.sidebar-toggle a {
|
||||
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: 1.2em;
|
||||
font-weight: 700;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.sidebar-element {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.right-sidebar-collapsed-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
font-size: 1.3em;
|
||||
margin: 0 -15px;
|
||||
}
|
||||
|
||||
.right-sidebar-collapsed-state:hover {
|
||||
background-color: #dbd9da;
|
||||
}
|
||||
|
||||
.old-comments-marker {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.old-comments-marker td {
|
||||
padding-top: 15px;
|
||||
border-bottom: 1px solid #dbd9da;
|
||||
}
|
||||
|
||||
#add_reviewer {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
### NAV SIDEBAR
|
||||
<aside class="right-sidebar right-sidebar-expanded" id="pr-nav-sticky" style="display: none">
|
||||
<div class="sidenav navbar__inner" >
|
||||
## TOGGLE
|
||||
<div class="sidebar-toggle" onclick="toggleSidebar(); return false">
|
||||
<a href="#toggleSidebar">
|
||||
<a href="#toggleSidebar" class="grey-link-action">
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -747,8 +554,12 @@
|
|||
|
||||
## RULES SUMMARY/RULES
|
||||
<div class="sidebar-element clear-both">
|
||||
<% vote_title = _ungettext(
|
||||
'Status calculated based on votes from {} reviewer',
|
||||
'Status calculated based on votes from {} reviewers', len(c.allowed_reviewers)).format(len(c.allowed_reviewers))
|
||||
%>
|
||||
|
||||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Reviewers')}">
|
||||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${vote_title}">
|
||||
<i class="icon-circle review-status-${c.pull_request_review_status}"></i>
|
||||
${len(c.allowed_reviewers)}
|
||||
</div>
|
||||
|
|
@ -769,7 +580,7 @@
|
|||
|
||||
## REVIEWERS
|
||||
<div class="right-sidebar-expanded-state pr-details-title">
|
||||
<span class="tooltip sidebar-heading" title="${_ungettext('Review status calculated based on {} reviewer vote', 'Review status calculated based on {} reviewers votes', len(c.allowed_reviewers)).format(len(c.allowed_reviewers))}">
|
||||
<span class="tooltip sidebar-heading" title="${vote_title}">
|
||||
<i class="icon-circle review-status-${c.pull_request_review_status}"></i>
|
||||
${_('Reviewers')}
|
||||
</span>
|
||||
|
|
@ -846,7 +657,7 @@
|
|||
|
||||
% if not c.at_version:
|
||||
% if c.resolved_comments:
|
||||
<span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.resolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
|
||||
<span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return toggleElement(this, '.resolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
|
||||
% else:
|
||||
<span class="block-right last-item noselect">Show resolved</span>
|
||||
% endif
|
||||
|
|
@ -863,7 +674,7 @@
|
|||
</table>
|
||||
% else:
|
||||
% if c.unresolved_comments + c.resolved_comments:
|
||||
${comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)}
|
||||
${sidebar.comments_table(c.unresolved_comments + c.resolved_comments, len(c.unresolved_comments), todo_comments=True)}
|
||||
% else:
|
||||
<table>
|
||||
<tr>
|
||||
|
|
@ -882,6 +693,8 @@
|
|||
<div class="tooltip right-sidebar-collapsed-state" style="display: none" onclick="toggleSidebar(); return false" title="${_('Comments')}">
|
||||
<i class="icon-comment" style="color: #949494"></i>
|
||||
<span id="comments-count">${len(c.inline_comments_flat+c.comments)}</span>
|
||||
<span class="display-none" id="general-comments-count">${len(c.comments)}</span>
|
||||
<span class="display-none" id="inline-comments-count">${len(c.inline_comments_flat)}</span>
|
||||
</div>
|
||||
|
||||
<div class="right-sidebar-expanded-state pr-details-title">
|
||||
|
|
@ -903,7 +716,7 @@
|
|||
</span>
|
||||
|
||||
% if outdated_comm_count_ver:
|
||||
<span class="block-right action_button last-item noselect" onclick="return versionController.toggleElement(this, '.hidden-comment');" data-toggle-on="Show outdated" data-toggle-off="Hide outdated">Show outdated</span>
|
||||
<span class="block-right action_button last-item noselect" onclick="return toggleElement(this, '.hidden-comment');" data-toggle-on="Show outdated" data-toggle-off="Hide outdated">Show outdated</span>
|
||||
% else:
|
||||
<span class="block-right last-item noselect">Show hidden</span>
|
||||
% endif
|
||||
|
|
@ -912,7 +725,7 @@
|
|||
|
||||
<div class="right-sidebar-expanded-state pr-details-content">
|
||||
% if c.inline_comments_flat + c.comments:
|
||||
${comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))}
|
||||
${sidebar.comments_table(c.inline_comments_flat + c.comments, len(c.inline_comments_flat+c.comments))}
|
||||
% else:
|
||||
<table>
|
||||
<tr>
|
||||
|
|
@ -942,7 +755,7 @@
|
|||
<div class="right-sidebar-expanded-state pr-details-content">
|
||||
<table>
|
||||
|
||||
<tr><td><code>${_('Pull Request Description')}</code></td></tr>
|
||||
<tr><td><code>${_('In pull request description')}:</code></td></tr>
|
||||
% if c.referenced_desc_issues:
|
||||
% for ticket_dict in c.referenced_desc_issues:
|
||||
<tr>
|
||||
|
|
@ -961,7 +774,7 @@
|
|||
</tr>
|
||||
% endif
|
||||
|
||||
<tr><td style="padding-top: 10px"><code>${_('Commit Messages')}</code></td></tr>
|
||||
<tr><td style="padding-top: 10px"><code>${_('In commit messages')}:</code></td></tr>
|
||||
% if c.referenced_commit_issues:
|
||||
% for ticket_dict in c.referenced_commit_issues:
|
||||
<tr>
|
||||
|
|
@ -992,451 +805,189 @@
|
|||
## This JS needs to be at the end
|
||||
<script type="text/javascript">
|
||||
|
||||
versionController = new VersionController();
|
||||
versionController.init();
|
||||
versionController = new VersionController();
|
||||
versionController.init();
|
||||
|
||||
reviewersController = new ReviewersController();
|
||||
commitsController = new CommitsController();
|
||||
reviewersController = new ReviewersController();
|
||||
commitsController = new CommitsController();
|
||||
|
||||
updateController = new UpdatePrController();
|
||||
updateController = new UpdatePrController();
|
||||
|
||||
/** leak object to top level scope **/
|
||||
window.PullRequestPresenceController;
|
||||
window.reviewerRulesData = ${c.pull_request_default_reviewers_data_json | n};
|
||||
window.setReviewersData = ${c.pull_request_set_reviewers_data_json | n};
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
window.PullRequestPresenceController = function (channel) {
|
||||
var self = this;
|
||||
this.channel = channel;
|
||||
this.users = {};
|
||||
// custom code mirror
|
||||
var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
|
||||
|
||||
this.storeUsers = function (users) {
|
||||
self.users = {}
|
||||
$.each(users, function(index, value) {
|
||||
var userId = value.state.id;
|
||||
self.users[userId] = value.state;
|
||||
})
|
||||
var PRDetails = {
|
||||
editButton: $('#open_edit_pullrequest'),
|
||||
closeButton: $('#close_edit_pullrequest'),
|
||||
deleteButton: $('#delete_pullrequest'),
|
||||
viewFields: $('#pr-desc, #pr-title'),
|
||||
editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
|
||||
|
||||
init: function () {
|
||||
var that = this;
|
||||
this.editButton.on('click', function (e) {
|
||||
that.edit();
|
||||
});
|
||||
this.closeButton.on('click', function (e) {
|
||||
that.view();
|
||||
});
|
||||
},
|
||||
|
||||
edit: function (event) {
|
||||
var cmInstance = $('#pr-description-input').get(0).MarkupForm.cm;
|
||||
this.viewFields.hide();
|
||||
this.editButton.hide();
|
||||
this.deleteButton.hide();
|
||||
this.closeButton.show();
|
||||
this.editFields.show();
|
||||
cmInstance.refresh();
|
||||
},
|
||||
|
||||
view: function (event) {
|
||||
this.editButton.show();
|
||||
this.deleteButton.show();
|
||||
this.editFields.hide();
|
||||
this.closeButton.hide();
|
||||
this.viewFields.show();
|
||||
}
|
||||
|
||||
this.render = function () {
|
||||
$.each($('.reviewer_entry'), function(index, value) {
|
||||
var userData = $(value).data();
|
||||
if(self.users[userData.reviewerUserId] !== undefined){
|
||||
$(value).find('.presence-state').show();
|
||||
} else {
|
||||
$(value).find('.presence-state').hide();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.handlePresence = function (data) {
|
||||
|
||||
if (data.type == 'presence' && data.channel === self.channel) {
|
||||
this.storeUsers(data.users);
|
||||
this.render()
|
||||
}
|
||||
};
|
||||
|
||||
this.handleChannelUpdate = function (data) {
|
||||
|
||||
if (data.channel === this.channel) {
|
||||
this.storeUsers(data.state.users);
|
||||
this.render()
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* subscribe our chat to topics that are interesting to it */
|
||||
$.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
|
||||
$.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
|
||||
};
|
||||
|
||||
PRDetails.init();
|
||||
ReviewersPanel.init(reviewerRulesData, setReviewersData);
|
||||
|
||||
window.showOutdated = function (self) {
|
||||
$('.comment-inline.comment-outdated').show();
|
||||
$('.filediff-outdated').show();
|
||||
$('.showOutdatedComments').hide();
|
||||
$('.hideOutdatedComments').show();
|
||||
};
|
||||
|
||||
window.hideOutdated = function (self) {
|
||||
$('.comment-inline.comment-outdated').hide();
|
||||
$('.filediff-outdated').hide();
|
||||
$('.hideOutdatedComments').hide();
|
||||
$('.showOutdatedComments').show();
|
||||
};
|
||||
|
||||
window.refreshMergeChecks = function () {
|
||||
var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
|
||||
$('.pull-request-merge').css('opacity', 0.3);
|
||||
$('.action-buttons-extra').css('opacity', 0.3);
|
||||
|
||||
$('.pull-request-merge').load(
|
||||
loadUrl, function () {
|
||||
$('.pull-request-merge').css('opacity', 1);
|
||||
|
||||
$('.action-buttons-extra').css('opacity', 1);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
window.closePullRequest = function (status) {
|
||||
if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
|
||||
return false;
|
||||
}
|
||||
// inject closing flag
|
||||
$('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
|
||||
$(generalCommentForm.statusChange).select2("val", status).trigger('change');
|
||||
$(generalCommentForm.submitForm).submit();
|
||||
};
|
||||
|
||||
//TODO this functionality is now missing
|
||||
$('#show-outdated-comments').on('click', function (e) {
|
||||
var button = $(this);
|
||||
var outdated = $('.comment-outdated');
|
||||
|
||||
if (button.html() === "(Show)") {
|
||||
button.html("(Hide)");
|
||||
outdated.show();
|
||||
} else {
|
||||
button.html("(Show)");
|
||||
outdated.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#merge_pull_request_form').submit(function () {
|
||||
if (!$('#merge_pull_request').attr('disabled')) {
|
||||
$('#merge_pull_request').attr('disabled', 'disabled');
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$('#edit_pull_request').on('click', function (e) {
|
||||
var title = $('#pr-title-input').val();
|
||||
var description = codeMirrorInstance.getValue();
|
||||
var renderer = $('#pr-renderer-input').val();
|
||||
editPullRequest(
|
||||
"${c.repo_name}", "${c.pull_request.pull_request_id}",
|
||||
title, description, renderer);
|
||||
});
|
||||
|
||||
$('#update_pull_request').on('click', function (e) {
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$(this).addClass('disabled');
|
||||
$(this).html(_gettext('Saving...'));
|
||||
reviewersController.updateReviewers(
|
||||
"${c.repo_name}", "${c.pull_request.pull_request_id}");
|
||||
});
|
||||
|
||||
// fixing issue with caches on firefox
|
||||
$('#update_commits').removeAttr("disabled");
|
||||
|
||||
$('.show-inline-comments').on('click', function (e) {
|
||||
var boxid = $(this).attr('data-comment-id');
|
||||
var button = $(this);
|
||||
|
||||
if (button.hasClass("comments-visible")) {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).hide();
|
||||
});
|
||||
button.removeClass("comments-visible");
|
||||
} else {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).show();
|
||||
});
|
||||
button.addClass("comments-visible");
|
||||
}
|
||||
});
|
||||
|
||||
$('.show-inline-comments').on('change', function (e) {
|
||||
var show = 'none';
|
||||
var target = e.currentTarget;
|
||||
if (target.checked) {
|
||||
show = ''
|
||||
}
|
||||
var boxid = $(target).attr('id_for');
|
||||
var comments = $('#{0} .inline-comments'.format(boxid));
|
||||
var fn_display = function (idx) {
|
||||
$(this).css('display', show);
|
||||
};
|
||||
$(comments).each(fn_display);
|
||||
var btns = $('#{0} .inline-comments-button'.format(boxid));
|
||||
$(btns).each(fn_display);
|
||||
});
|
||||
|
||||
// register submit callback on commentForm form to track TODOs
|
||||
window.commentFormGlobalSubmitSuccessCallback = function () {
|
||||
refreshMergeChecks();
|
||||
};
|
||||
|
||||
ReviewerAutoComplete('#user');
|
||||
|
||||
})();
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$(function () {
|
||||
var channel = '${c.pr_broadcast_channel}';
|
||||
new ReviewerPresenceController(channel)
|
||||
|
||||
// custom code mirror
|
||||
var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
|
||||
|
||||
var PRDetails = {
|
||||
editButton: $('#open_edit_pullrequest'),
|
||||
closeButton: $('#close_edit_pullrequest'),
|
||||
deleteButton: $('#delete_pullrequest'),
|
||||
viewFields: $('#pr-desc, #pr-title'),
|
||||
editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
|
||||
|
||||
init: function () {
|
||||
var that = this;
|
||||
this.editButton.on('click', function (e) {
|
||||
that.edit();
|
||||
});
|
||||
this.closeButton.on('click', function (e) {
|
||||
that.view();
|
||||
});
|
||||
},
|
||||
|
||||
edit: function (event) {
|
||||
this.viewFields.hide();
|
||||
this.editButton.hide();
|
||||
this.deleteButton.hide();
|
||||
this.closeButton.show();
|
||||
this.editFields.show();
|
||||
codeMirrorInstance.refresh();
|
||||
},
|
||||
|
||||
view: function (event) {
|
||||
this.editButton.show();
|
||||
this.deleteButton.show();
|
||||
this.editFields.hide();
|
||||
this.closeButton.hide();
|
||||
this.viewFields.show();
|
||||
}
|
||||
};
|
||||
|
||||
var ReviewersPanel = {
|
||||
editButton: $('#open_edit_reviewers'),
|
||||
closeButton: $('#close_edit_reviewers'),
|
||||
addButton: $('#add_reviewer'),
|
||||
removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
|
||||
reviewRules: ${c.pull_request_default_reviewers_data_json | n},
|
||||
setReviewers: ${c.pull_request_set_reviewers_data_json | n},
|
||||
|
||||
init: function () {
|
||||
var self = this;
|
||||
this.editButton.on('click', function (e) {
|
||||
self.edit();
|
||||
});
|
||||
this.closeButton.on('click', function (e) {
|
||||
self.close();
|
||||
self.renderReviewers();
|
||||
});
|
||||
|
||||
self.renderReviewers();
|
||||
|
||||
},
|
||||
|
||||
renderReviewers: function () {
|
||||
|
||||
$('#review_members').html('')
|
||||
$.each(this.setReviewers.reviewers, function (key, val) {
|
||||
var member = val;
|
||||
|
||||
var entry = renderTemplate('reviewMemberEntry', {
|
||||
'member': member,
|
||||
'mandatory': member.mandatory,
|
||||
'reasons': member.reasons,
|
||||
'allowed_to_update': member.allowed_to_update,
|
||||
'review_status': member.review_status,
|
||||
'review_status_label': member.review_status_label,
|
||||
'user_group': member.user_group,
|
||||
'create': false
|
||||
});
|
||||
|
||||
$('#review_members').append(entry)
|
||||
});
|
||||
tooltipActivate();
|
||||
|
||||
},
|
||||
|
||||
edit: function (event) {
|
||||
this.editButton.hide();
|
||||
this.closeButton.show();
|
||||
this.addButton.show();
|
||||
$(this.removeButtons.selector).css('visibility', 'visible');
|
||||
// review rules
|
||||
reviewersController.loadReviewRules(this.reviewRules);
|
||||
},
|
||||
|
||||
close: function (event) {
|
||||
this.editButton.show();
|
||||
this.closeButton.hide();
|
||||
this.addButton.hide();
|
||||
$(this.removeButtons.selector).css('visibility', 'hidden');
|
||||
// hide review rules
|
||||
reviewersController.hideReviewRules()
|
||||
}
|
||||
};
|
||||
|
||||
PRDetails.init();
|
||||
ReviewersPanel.init();
|
||||
|
||||
showOutdated = function (self) {
|
||||
$('.comment-inline.comment-outdated').show();
|
||||
$('.filediff-outdated').show();
|
||||
$('.showOutdatedComments').hide();
|
||||
$('.hideOutdatedComments').show();
|
||||
};
|
||||
|
||||
hideOutdated = function (self) {
|
||||
$('.comment-inline.comment-outdated').hide();
|
||||
$('.filediff-outdated').hide();
|
||||
$('.hideOutdatedComments').hide();
|
||||
$('.showOutdatedComments').show();
|
||||
};
|
||||
|
||||
refreshMergeChecks = function () {
|
||||
var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
|
||||
$('.pull-request-merge').css('opacity', 0.3);
|
||||
$('.action-buttons-extra').css('opacity', 0.3);
|
||||
|
||||
$('.pull-request-merge').load(
|
||||
loadUrl, function () {
|
||||
$('.pull-request-merge').css('opacity', 1);
|
||||
|
||||
$('.action-buttons-extra').css('opacity', 1);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
refreshComments = function () {
|
||||
var params = {
|
||||
'pull_request_id': templateContext.pull_request_data.pull_request_id,
|
||||
'repo_name': templateContext.repo_name,
|
||||
'version': '${request.GET.get('version', '')}',
|
||||
};
|
||||
var data = {"comments[]": ["1"]};
|
||||
var loadUrl = pyroutes.url('pullrequest_comments', params);
|
||||
var $targetElem = $('.comments-content-table');
|
||||
$targetElem.css('opacity', 0.3);
|
||||
$targetElem.load(
|
||||
loadUrl, data, function (responseText, textStatus, jqXHR) {
|
||||
if (jqXHR.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
var $counterElem = $('#comments-count');
|
||||
var newCount = $(responseText).data('counter');
|
||||
if (newCount !== undefined) {
|
||||
var callback = function () {
|
||||
$counterElem.animate({'opacity': 1.00}, 200)
|
||||
$counterElem.html(newCount);
|
||||
};
|
||||
$counterElem.animate({'opacity': 0.15}, 200, callback);
|
||||
}
|
||||
|
||||
|
||||
$targetElem.css('opacity', 1);
|
||||
tooltipActivate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
refreshTODOs = function () {
|
||||
var params = {
|
||||
'pull_request_id': templateContext.pull_request_data.pull_request_id,
|
||||
'repo_name': templateContext.repo_name,
|
||||
'version': '${request.GET.get('version', '')}',
|
||||
};
|
||||
var data = {"comments[]": ["1"]};
|
||||
var loadUrl = pyroutes.url('pullrequest_todos', params);
|
||||
var $targetElem = $('.todos-content-table');
|
||||
$targetElem.css('opacity', 0.3);
|
||||
$targetElem.load(
|
||||
loadUrl, data, function (responseText, textStatus, jqXHR) {
|
||||
if (jqXHR.status !== 200) {
|
||||
return false;
|
||||
}
|
||||
var $counterElem = $('#todos-count')
|
||||
var newCount = $(responseText).data('counter');
|
||||
if (newCount !== undefined) {
|
||||
var callback = function () {
|
||||
$counterElem.animate({'opacity': 1.00}, 200)
|
||||
$counterElem.html(newCount);
|
||||
};
|
||||
$counterElem.animate({'opacity': 0.15}, 200, callback);
|
||||
}
|
||||
|
||||
$targetElem.css('opacity', 1);
|
||||
tooltipActivate();
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
refreshAllComments = function() {
|
||||
refreshComments();
|
||||
refreshTODOs();
|
||||
}
|
||||
|
||||
closePullRequest = function (status) {
|
||||
if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
|
||||
return false;
|
||||
}
|
||||
// inject closing flag
|
||||
$('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
|
||||
$(generalCommentForm.statusChange).select2("val", status).trigger('change');
|
||||
$(generalCommentForm.submitForm).submit();
|
||||
};
|
||||
|
||||
$('#show-outdated-comments').on('click', function (e) {
|
||||
var button = $(this);
|
||||
var outdated = $('.comment-outdated');
|
||||
|
||||
if (button.html() === "(Show)") {
|
||||
button.html("(Hide)");
|
||||
outdated.show();
|
||||
} else {
|
||||
button.html("(Show)");
|
||||
outdated.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('.show-inline-comments').on('change', function (e) {
|
||||
var show = 'none';
|
||||
var target = e.currentTarget;
|
||||
if (target.checked) {
|
||||
show = ''
|
||||
}
|
||||
var boxid = $(target).attr('id_for');
|
||||
var comments = $('#{0} .inline-comments'.format(boxid));
|
||||
var fn_display = function (idx) {
|
||||
$(this).css('display', show);
|
||||
};
|
||||
$(comments).each(fn_display);
|
||||
var btns = $('#{0} .inline-comments-button'.format(boxid));
|
||||
$(btns).each(fn_display);
|
||||
});
|
||||
|
||||
$('#merge_pull_request_form').submit(function () {
|
||||
if (!$('#merge_pull_request').attr('disabled')) {
|
||||
$('#merge_pull_request').attr('disabled', 'disabled');
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$('#edit_pull_request').on('click', function (e) {
|
||||
var title = $('#pr-title-input').val();
|
||||
var description = codeMirrorInstance.getValue();
|
||||
var renderer = $('#pr-renderer-input').val();
|
||||
editPullRequest(
|
||||
"${c.repo_name}", "${c.pull_request.pull_request_id}",
|
||||
title, description, renderer);
|
||||
});
|
||||
|
||||
$('#update_pull_request').on('click', function (e) {
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$(this).addClass('disabled');
|
||||
$(this).html(_gettext('Saving...'));
|
||||
reviewersController.updateReviewers(
|
||||
"${c.repo_name}", "${c.pull_request.pull_request_id}");
|
||||
});
|
||||
|
||||
|
||||
// fixing issue with caches on firefox
|
||||
$('#update_commits').removeAttr("disabled");
|
||||
|
||||
$('.show-inline-comments').on('click', function (e) {
|
||||
var boxid = $(this).attr('data-comment-id');
|
||||
var button = $(this);
|
||||
|
||||
if (button.hasClass("comments-visible")) {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).hide();
|
||||
});
|
||||
button.removeClass("comments-visible");
|
||||
} else {
|
||||
$('#{0} .inline-comments'.format(boxid)).each(function (index) {
|
||||
$(this).show();
|
||||
});
|
||||
button.addClass("comments-visible");
|
||||
}
|
||||
});
|
||||
|
||||
// register submit callback on commentForm form to track TODOs
|
||||
window.commentFormGlobalSubmitSuccessCallback = function () {
|
||||
refreshMergeChecks();
|
||||
};
|
||||
|
||||
ReviewerAutoComplete('#user');
|
||||
|
||||
})
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
var $sideBar = $('.right-sidebar');
|
||||
var marginExpVal = '320'
|
||||
var marginColVal = '50'
|
||||
var marginExpanded = {'margin': '0 {0}px 0 0'.format(marginExpVal)};
|
||||
var marginCollapsed = {'margin': '0 {0}px 0 0'.format(marginColVal)};
|
||||
var marginExpandedHeader = {'margin': '0 -{0}px 0 0'.format(marginExpVal), 'z-index': 10000};
|
||||
var marginCollapsedHeader = {'margin': '0 -{0}px 0 0'.format(marginColVal), 'z-index': 10000};
|
||||
|
||||
var updateStickyHeader = function() {
|
||||
if (window.updateSticky !== undefined) {
|
||||
// potentially our comments change the active window size, so we
|
||||
// notify sticky elements
|
||||
updateSticky()
|
||||
}
|
||||
}
|
||||
|
||||
var expandSidebar = function() {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
$('.outerwrapper').css(marginExpanded);
|
||||
$('.header').css(marginExpandedHeader);
|
||||
$('.sidebar-toggle a').html('<i class="icon-right" style="margin-right: -10px"></i><i class="icon-right"></i>');
|
||||
$('.right-sidebar-collapsed-state').hide();
|
||||
$('.right-sidebar-expanded-state').show();
|
||||
|
||||
$sideBar.addClass('right-sidebar-expanded')
|
||||
$sideBar.removeClass('right-sidebar-collapsed')
|
||||
}
|
||||
|
||||
var collapseSidebar = function() {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
$('.outerwrapper').css(marginCollapsed);
|
||||
$('.header').css(marginCollapsedHeader);
|
||||
$('.sidebar-toggle a').html('<i class="icon-left" style="margin-right: -10px"></i><i class="icon-left"></i>');
|
||||
$('.right-sidebar-collapsed-state').show();
|
||||
$('.right-sidebar-expanded-state').hide();
|
||||
|
||||
$sideBar.removeClass('right-sidebar-expanded')
|
||||
$sideBar.addClass('right-sidebar-collapsed')
|
||||
}
|
||||
|
||||
toggleSidebar = function () {
|
||||
var $sideBar = $('.right-sidebar');
|
||||
|
||||
if ($sideBar.hasClass('right-sidebar-expanded')) {
|
||||
// expanded -> collapsed transition
|
||||
collapseSidebar();
|
||||
var sidebarState = 'collapsed';
|
||||
|
||||
} else {
|
||||
// collapsed -> expanded
|
||||
expandSidebar();
|
||||
var sidebarState = 'expanded';
|
||||
}
|
||||
|
||||
// update our other sticky header in same context
|
||||
updateStickyHeader();
|
||||
storeUserSessionAttr('rc_user_session_attr.sidebarState', sidebarState);
|
||||
}
|
||||
|
||||
var expanded = $sideBar.hasClass('right-sidebar-expanded');
|
||||
|
||||
if (templateContext.session_attrs.sidebarState === 'expanded') {
|
||||
expanded = true
|
||||
} else if (templateContext.session_attrs.sidebarState === 'collapsed') {
|
||||
expanded = false
|
||||
}
|
||||
|
||||
// show sidebar since it's hidden on load
|
||||
$('.right-sidebar').show();
|
||||
|
||||
// init based on set initial class, or if defined user session attrs
|
||||
if (expanded) {
|
||||
expandSidebar();
|
||||
updateStickyHeader();
|
||||
|
||||
} else {
|
||||
collapseSidebar();
|
||||
updateStickyHeader();
|
||||
}
|
||||
var channel = '${c.pr_broadcast_channel}';
|
||||
new PullRequestPresenceController(channel)
|
||||
|
||||
})
|
||||
</script>
|
||||
})
|
||||
</script>
|
||||
|
||||
</%def>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue