pullrequests.js
890 lines
| 27.9 KiB
| application/javascript
|
JavascriptLexer
r4306 | // # Copyright (C) 2010-2020 RhodeCode GmbH | |||
r1 | // # | |||
// # This program is free software: you can redistribute it and/or modify | ||||
// # it under the terms of the GNU Affero General Public License, version 3 | ||||
// # (only), as published by the Free Software Foundation. | ||||
// # | ||||
// # This program is distributed in the hope that it will be useful, | ||||
// # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
// # GNU General Public License for more details. | ||||
// # | ||||
// # You should have received a copy of the GNU Affero General Public License | ||||
// # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
// # | ||||
// # This program is dual-licensed. If you wish to learn more about the | ||||
// # RhodeCode Enterprise Edition, including its added features, Support services, | ||||
// # and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
r1769 | ||||
var prButtonLockChecks = { | ||||
'compare': false, | ||||
'reviewers': false | ||||
}; | ||||
r1 | /** | |||
r1769 | * lock button until all checks and loads are made. E.g reviewer calculation | |||
* should prevent from submitting a PR | ||||
* @param lockEnabled | ||||
* @param msg | ||||
* @param scope | ||||
r1 | */ | |||
r1769 | var prButtonLock = function(lockEnabled, msg, scope) { | |||
scope = scope || 'all'; | ||||
if (scope == 'all'){ | ||||
prButtonLockChecks['compare'] = !lockEnabled; | ||||
prButtonLockChecks['reviewers'] = !lockEnabled; | ||||
} else if (scope == 'compare') { | ||||
prButtonLockChecks['compare'] = !lockEnabled; | ||||
} else if (scope == 'reviewers'){ | ||||
prButtonLockChecks['reviewers'] = !lockEnabled; | ||||
} | ||||
var checksMeet = prButtonLockChecks.compare && prButtonLockChecks.reviewers; | ||||
if (lockEnabled) { | ||||
r2806 | $('#pr_submit').attr('disabled', 'disabled'); | |||
r1769 | } | |||
else if (checksMeet) { | ||||
r2806 | $('#pr_submit').removeAttr('disabled'); | |||
r1769 | } | |||
r1 | ||||
r1769 | if (msg) { | |||
$('#pr_open_message').html(msg); | ||||
} | ||||
}; | ||||
r1 | ||||
r1769 | ||||
/** | ||||
Generate Title and Description for a PullRequest. | ||||
In case of 1 commits, the title and description is that one commit | ||||
in case of multiple commits, we iterate on them with max N number of commits, | ||||
and build description in a form | ||||
- commitN | ||||
- commitN+1 | ||||
... | ||||
Title is then constructed from branch names, or other references, | ||||
replacing '-' and '_' into spaces | ||||
* @param sourceRef | ||||
* @param elements | ||||
* @param limit | ||||
* @returns {*[]} | ||||
*/ | ||||
r4433 | var getTitleAndDescription = function(sourceRefType, sourceRef, elements, limit) { | |||
r1769 | var title = ''; | |||
var desc = ''; | ||||
$.each($(elements).get().reverse().slice(0, limit), function(idx, value) { | ||||
r4346 | var rawMessage = value['message']; | |||
r1769 | desc += '- ' + rawMessage.split('\n')[0].replace(/\n+$/, "") + '\n'; | |||
}); | ||||
// only 1 commit, use commit message as title | ||||
if (elements.length === 1) { | ||||
r4346 | var rawMessage = elements[0]['message']; | |||
r4163 | title = rawMessage.split('\n')[0]; | |||
r1769 | } | |||
else { | ||||
// use reference name | ||||
r4433 | var normalizedRef = sourceRef.replace(/-/g, ' ').replace(/_/g, ' ').capitalizeFirstLetter() | |||
var refType = sourceRefType; | ||||
title = 'Changes from {0}: {1}'.format(refType, normalizedRef); | ||||
r1769 | } | |||
return [title, desc] | ||||
r1 | }; | |||
r1769 | ||||
ReviewersController = function () { | ||||
var self = this; | ||||
this.$reviewRulesContainer = $('#review_rules'); | ||||
this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules'); | ||||
r4482 | this.$userRule = $('.pr-user-rule-container'); | |||
r1769 | this.forbidReviewUsers = undefined; | |||
this.$reviewMembers = $('#review_members'); | ||||
this.currentRequest = null; | ||||
r4346 | this.diffData = null; | |||
r4482 | this.enabledRules = []; | |||
r4346 | //dummy handler, we might register our own later | |||
this.diffDataHandler = function(data){}; | ||||
r1769 | ||||
r4346 | this.defaultForbidReviewUsers = function () { | |||
r1769 | return [ | |||
r4346 | { | |||
'username': 'default', | ||||
'user_id': templateContext.default_user.user_id | ||||
} | ||||
r1769 | ]; | |||
}; | ||||
r4346 | this.hideReviewRules = function () { | |||
r1769 | self.$reviewRulesContainer.hide(); | |||
r4482 | $(self.$userRule.selector).hide(); | |||
r1769 | }; | |||
r4346 | this.showReviewRules = function () { | |||
r1769 | self.$reviewRulesContainer.show(); | |||
r4482 | $(self.$userRule.selector).show(); | |||
r1769 | }; | |||
r4346 | this.addRule = function (ruleText) { | |||
r1769 | self.showReviewRules(); | |||
r4482 | self.enabledRules.push(ruleText); | |||
r1769 | return '<div>- {0}</div>'.format(ruleText) | |||
}; | ||||
r4346 | this.loadReviewRules = function (data) { | |||
self.diffData = data; | ||||
r1769 | // reset forbidden Users | |||
this.forbidReviewUsers = self.defaultForbidReviewUsers(); | ||||
// reset state of review rules | ||||
self.$rulesList.html(''); | ||||
if (!data || data.rules === undefined || $.isEmptyObject(data.rules)) { | ||||
// default rule, case for older repo that don't have any rules stored | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('All reviewers must vote.')) | ||||
); | ||||
return self.forbidReviewUsers | ||||
} | ||||
if (data.rules.voting !== undefined) { | ||||
r2484 | if (data.rules.voting < 0) { | |||
r1769 | self.$rulesList.append( | |||
self.addRule( | ||||
r4346 | _gettext('All individual reviewers must vote.')) | |||
r1769 | ) | |||
} else if (data.rules.voting === 1) { | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('At least {0} reviewer must vote.').format(data.rules.voting)) | ||||
) | ||||
} else { | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('At least {0} reviewers must vote.').format(data.rules.voting)) | ||||
) | ||||
} | ||||
} | ||||
r2484 | ||||
if (data.rules.voting_groups !== undefined) { | ||||
r4346 | $.each(data.rules.voting_groups, function (index, rule_data) { | |||
r2484 | self.$rulesList.append( | |||
self.addRule(rule_data.text) | ||||
) | ||||
}); | ||||
} | ||||
r1769 | if (data.rules.use_code_authors_for_review) { | |||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('Reviewers picked from source code changes.')) | ||||
) | ||||
} | ||||
r4482 | ||||
r1769 | if (data.rules.forbid_adding_reviewers) { | |||
$('#add_reviewer_input').remove(); | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('Adding new reviewers is forbidden.')) | ||||
) | ||||
} | ||||
r4482 | ||||
r1769 | if (data.rules.forbid_author_to_review) { | |||
self.forbidReviewUsers.push(data.rules_data.pr_author); | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('Author is not allowed to be a reviewer.')) | ||||
) | ||||
} | ||||
r4482 | ||||
r1787 | if (data.rules.forbid_commit_author_to_review) { | |||
if (data.rules_data.forbidden_users) { | ||||
r4346 | $.each(data.rules_data.forbidden_users, function (index, member_data) { | |||
r1787 | self.forbidReviewUsers.push(member_data) | |||
}); | ||||
} | ||||
self.$rulesList.append( | ||||
self.addRule( | ||||
_gettext('Commit Authors are not allowed to be a reviewer.')) | ||||
) | ||||
} | ||||
r4482 | // we don't have any rules set, so we inform users about it | |||
if (self.enabledRules.length === 0) { | ||||
self.addRule( | ||||
_gettext('No review rules set.')) | ||||
} | ||||
r1769 | return self.forbidReviewUsers | |||
}; | ||||
r4346 | this.loadDefaultReviewers = function (sourceRepo, sourceRef, targetRepo, targetRef) { | |||
r1769 | ||||
if (self.currentRequest) { | ||||
r4346 | // make sure we cleanup old running requests before triggering this again | |||
r1769 | self.currentRequest.abort(); | |||
r821 | } | |||
r1769 | ||||
$('.calculate-reviewers').show(); | ||||
// reset reviewer members | ||||
self.$reviewMembers.empty(); | ||||
prButtonLock(true, null, 'reviewers'); | ||||
$('#user').hide(); // hide user autocomplete before load | ||||
r4346 | // lock PR button, so we cannot send PR before it's calculated | |||
prButtonLock(true, _gettext('Loading diff ...'), 'compare'); | ||||
r2555 | if (sourceRef.length !== 3 || targetRef.length !== 3) { | |||
// don't load defaults in case we're missing some refs... | ||||
$('.calculate-reviewers').hide(); | ||||
return | ||||
} | ||||
r1769 | var url = pyroutes.url('repo_default_reviewers_data', | |||
r4346 | { | |||
'repo_name': templateContext.repo_name, | ||||
'source_repo': sourceRepo, | ||||
'source_ref': sourceRef[2], | ||||
'target_repo': targetRepo, | ||||
'target_ref': targetRef[2] | ||||
}); | ||||
r1769 | ||||
r4346 | self.currentRequest = $.ajax({ | |||
url: url, | ||||
headers: {'X-PARTIAL-XHR': true}, | ||||
type: 'GET', | ||||
success: function (data) { | ||||
r1769 | self.currentRequest = null; | |||
// review rules | ||||
self.loadReviewRules(data); | ||||
r4346 | self.handleDiffData(data["diff_info"]); | |||
r1769 | ||||
for (var i = 0; i < data.reviewers.length; i++) { | ||||
r4346 | var reviewer = data.reviewers[i]; | |||
self.addReviewMember(reviewer, reviewer.reasons, reviewer.mandatory); | ||||
r1769 | } | |||
$('.calculate-reviewers').hide(); | ||||
prButtonLock(false, null, 'reviewers'); | ||||
$('#user').show(); // show user autocomplete after load | ||||
r4346 | ||||
var commitElements = data["diff_info"]['commits']; | ||||
r4485 | ||||
r4346 | if (commitElements.length === 0) { | |||
r4485 | var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format( | |||
_gettext('There are no commits to merge.')); | ||||
prButtonLock(true, noCommitsMsg, 'all'); | ||||
r4346 | ||||
} else { | ||||
// un-lock PR button, so we cannot send PR before it's calculated | ||||
prButtonLock(false, null, 'compare'); | ||||
} | ||||
}, | ||||
error: function (jqXHR, textStatus, errorThrown) { | ||||
var prefix = "Loading diff and reviewers failed\n" | ||||
var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix); | ||||
ajaxErrorSwal(message); | ||||
} | ||||
}); | ||||
r1769 | }; | |||
// check those, refactor | ||||
r4346 | this.removeReviewMember = function (reviewer_id, mark_delete) { | |||
r1769 | var reviewer = $('#reviewer_{0}'.format(reviewer_id)); | |||
r4346 | if (typeof (mark_delete) === undefined) { | |||
r1769 | mark_delete = false; | |||
} | ||||
r4346 | if (mark_delete === true) { | |||
if (reviewer) { | ||||
r1769 | // now delete the input | |||
$('#reviewer_{0} input'.format(reviewer_id)).remove(); | ||||
// mark as to-delete | ||||
var obj = $('#reviewer_{0}_name'.format(reviewer_id)); | ||||
obj.addClass('to-delete'); | ||||
r4346 | obj.css({"text-decoration": "line-through", "opacity": 0.5}); | |||
r1769 | } | |||
r4346 | } else { | |||
r1769 | $('#reviewer_{0}'.format(reviewer_id)).remove(); | |||
} | ||||
}; | ||||
r4346 | ||||
this.reviewMemberEntry = function () { | ||||
r1769 | ||||
r2484 | }; | |||
r4346 | ||||
this.addReviewMember = function (reviewer_obj, reasons, mandatory) { | ||||
r2484 | var id = reviewer_obj.user_id; | |||
var username = reviewer_obj.username; | ||||
r1769 | var reasons = reasons || []; | |||
var mandatory = mandatory || false; | ||||
r873 | ||||
r2484 | // register IDS to check if we don't have this ID already in | |||
var currentIds = []; | ||||
r4485 | ||||
$.each(self.$reviewMembers.find('.reviewer_entry'), function (index, value) { | ||||
currentIds.push($(value).data('reviewerUserId')) | ||||
}) | ||||
r1769 | ||||
r4346 | var userAllowedReview = function (userId) { | |||
r1769 | var allowed = true; | |||
r4346 | $.each(self.forbidReviewUsers, function (index, member_data) { | |||
r1769 | if (parseInt(userId) === member_data['user_id']) { | |||
allowed = false; | ||||
return false // breaks the loop | ||||
} | ||||
}); | ||||
return allowed | ||||
}; | ||||
var userAllowed = userAllowedReview(id); | ||||
r4346 | if (!userAllowed) { | |||
alert(_gettext('User `{0}` not allowed to be a reviewer').format(username)); | ||||
r2484 | } else { | |||
// only add if it's not there | ||||
r4485 | var alreadyReviewer = currentIds.indexOf(id) != -1; | |||
r1769 | ||||
r2484 | if (alreadyReviewer) { | |||
alert(_gettext('User `{0}` already in reviewers').format(username)); | ||||
} else { | ||||
r4485 | var reviewerEntry = renderTemplate('reviewMemberEntry', { | |||
r4346 | 'member': reviewer_obj, | |||
'mandatory': mandatory, | ||||
r4482 | 'reasons': reasons, | |||
r4346 | 'allowed_to_update': true, | |||
'review_status': 'not_reviewed', | ||||
'review_status_label': _gettext('Not Reviewed'), | ||||
r4482 | 'user_group': reviewer_obj.user_group, | |||
'create': true, | ||||
r4485 | 'rule_show': true, | |||
}) | ||||
$(self.$reviewMembers.selector).append(reviewerEntry); | ||||
r4026 | tooltipActivate(); | |||
r2484 | } | |||
r1769 | } | |||
}; | ||||
r4346 | this.updateReviewers = function (repo_name, pull_request_id) { | |||
r2484 | var postData = $('#reviewers input').serialize(); | |||
r1769 | _updatePullRequest(repo_name, pull_request_id, postData); | |||
}; | ||||
r1 | ||||
r4346 | this.handleDiffData = function (data) { | |||
self.diffDataHandler(data) | ||||
} | ||||
r1 | }; | |||
r1769 | ||||
r1 | var _updatePullRequest = function(repo_name, pull_request_id, postData) { | |||
var url = pyroutes.url( | ||||
'pullrequest_update', | ||||
{"repo_name": repo_name, "pull_request_id": pull_request_id}); | ||||
r873 | if (typeof postData === 'string' ) { | |||
postData += '&csrf_token=' + CSRF_TOKEN; | ||||
} else { | ||||
postData.csrf_token = CSRF_TOKEN; | ||||
} | ||||
r4101 | ||||
r1 | var success = function(o) { | |||
r4101 | var redirectUrl = o['redirect_url']; | |||
if (redirectUrl !== undefined && redirectUrl !== null && redirectUrl !== '') { | ||||
window.location = redirectUrl; | ||||
} else { | ||||
window.location.reload(); | ||||
} | ||||
r1 | }; | |||
r4101 | ||||
r1 | ajaxPOST(url, postData, success); | |||
}; | ||||
/** | ||||
* PULL REQUEST update commits | ||||
*/ | ||||
r4101 | var updateCommits = function(repo_name, pull_request_id, force) { | |||
r1 | var postData = { | |||
r4101 | 'update_commits': true | |||
}; | ||||
if (force !== undefined && force === true) { | ||||
postData['force_refresh'] = true | ||||
} | ||||
r1 | _updatePullRequest(repo_name, pull_request_id, postData); | |||
}; | ||||
/** | ||||
* PULL REQUEST edit info | ||||
*/ | ||||
r2903 | var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) { | |||
r1 | var url = pyroutes.url( | |||
'pullrequest_update', | ||||
{"repo_name": repo_name, "pull_request_id": pull_request_id}); | ||||
var postData = { | ||||
'title': title, | ||||
'description': description, | ||||
r2903 | 'description_renderer': renderer, | |||
r1 | 'edit_pull_request': true, | |||
'csrf_token': CSRF_TOKEN | ||||
}; | ||||
var success = function(o) { | ||||
window.location.reload(); | ||||
}; | ||||
ajaxPOST(url, postData, success); | ||||
}; | ||||
/** | ||||
* Reviewer autocomplete | ||||
*/ | ||||
r1678 | var ReviewerAutoComplete = function(inputId) { | |||
$(inputId).autocomplete({ | ||||
r1 | serviceUrl: pyroutes.url('user_autocomplete_data'), | |||
minChars:2, | ||||
maxHeight:400, | ||||
deferRequestBy: 300, //miliseconds | ||||
showNoSuggestionNotice: true, | ||||
tabDisabled: true, | ||||
autoSelectFirst: true, | ||||
r1769 | params: { user_id: templateContext.rhodecode_user.user_id, user_groups:true, user_groups_expand:true, skip_default_user:true }, | |||
r1 | formatResult: autocompleteFormatResult, | |||
lookupFilter: autocompleteFilterResult, | ||||
r1678 | onSelect: function(element, data) { | |||
r2484 | var mandatory = false; | |||
var reasons = [_gettext('added manually by "{0}"').format(templateContext.rhodecode_user.username)]; | ||||
r1678 | ||||
r2484 | // add whole user groups | |||
r1678 | if (data.value_type == 'user_group') { | |||
reasons.push(_gettext('member of "{0}"').format(data.value_display)); | ||||
$.each(data.members, function(index, member_data) { | ||||
r2484 | var reviewer = member_data; | |||
reviewer['user_id'] = member_data['id']; | ||||
reviewer['gravatar_link'] = member_data['icon_link']; | ||||
reviewer['user_link'] = member_data['profile_link']; | ||||
reviewer['rules'] = []; | ||||
reviewersController.addReviewMember(reviewer, reasons, mandatory); | ||||
r1678 | }) | |||
r2484 | } | |||
// add single user | ||||
else { | ||||
var reviewer = data; | ||||
reviewer['user_id'] = data['id']; | ||||
reviewer['gravatar_link'] = data['icon_link']; | ||||
reviewer['user_link'] = data['profile_link']; | ||||
reviewer['rules'] = []; | ||||
reviewersController.addReviewMember(reviewer, reasons, mandatory); | ||||
r1678 | } | |||
$(inputId).val(''); | ||||
r1 | } | |||
}); | ||||
}; | ||||
r1371 | ||||
r4485 | window.VersionController = function () { | |||
r1371 | var self = this; | |||
this.$verSource = $('input[name=ver_source]'); | ||||
this.$verTarget = $('input[name=ver_target]'); | ||||
this.$showVersionDiff = $('#show-version-diff'); | ||||
this.adjustRadioSelectors = function (curNode) { | ||||
var getVal = function (item) { | ||||
if (item == 'latest') { | ||||
return Number.MAX_SAFE_INTEGER | ||||
} | ||||
else { | ||||
return parseInt(item) | ||||
} | ||||
}; | ||||
var curVal = getVal($(curNode).val()); | ||||
var cleared = false; | ||||
$.each(self.$verSource, function (index, value) { | ||||
var elVal = getVal($(value).val()); | ||||
if (elVal > curVal) { | ||||
if ($(value).is(':checked')) { | ||||
cleared = true; | ||||
} | ||||
$(value).attr('disabled', 'disabled'); | ||||
$(value).removeAttr('checked'); | ||||
$(value).css({'opacity': 0.1}); | ||||
} | ||||
else { | ||||
$(value).css({'opacity': 1}); | ||||
$(value).removeAttr('disabled'); | ||||
} | ||||
}); | ||||
if (cleared) { | ||||
// if we unchecked an active, set the next one to same loc. | ||||
$(this.$verSource).filter('[value={0}]'.format( | ||||
curVal)).attr('checked', 'checked'); | ||||
} | ||||
self.setLockAction(false, | ||||
$(curNode).data('verPos'), | ||||
$(this.$verSource).filter(':checked').data('verPos') | ||||
); | ||||
}; | ||||
this.attachVersionListener = function () { | ||||
self.$verTarget.change(function (e) { | ||||
self.adjustRadioSelectors(this) | ||||
}); | ||||
self.$verSource.change(function (e) { | ||||
self.adjustRadioSelectors(self.$verTarget.filter(':checked')) | ||||
}); | ||||
}; | ||||
this.init = function () { | ||||
var curNode = self.$verTarget.filter(':checked'); | ||||
self.adjustRadioSelectors(curNode); | ||||
self.setLockAction(true); | ||||
self.attachVersionListener(); | ||||
}; | ||||
this.setLockAction = function (state, selectedVersion, otherVersion) { | ||||
var $showVersionDiff = this.$showVersionDiff; | ||||
if (state) { | ||||
$showVersionDiff.attr('disabled', 'disabled'); | ||||
$showVersionDiff.addClass('disabled'); | ||||
$showVersionDiff.html($showVersionDiff.data('labelTextLocked')); | ||||
} | ||||
else { | ||||
$showVersionDiff.removeAttr('disabled'); | ||||
$showVersionDiff.removeClass('disabled'); | ||||
if (selectedVersion == otherVersion) { | ||||
$showVersionDiff.html($showVersionDiff.data('labelTextShow')); | ||||
} else { | ||||
$showVersionDiff.html($showVersionDiff.data('labelTextDiff')); | ||||
} | ||||
} | ||||
}; | ||||
this.showVersionDiff = function () { | ||||
var target = self.$verTarget.filter(':checked'); | ||||
var source = self.$verSource.filter(':checked'); | ||||
if (target.val() && source.val()) { | ||||
var params = { | ||||
'pull_request_id': templateContext.pull_request_data.pull_request_id, | ||||
'repo_name': templateContext.repo_name, | ||||
'version': target.val(), | ||||
'from_version': source.val() | ||||
}; | ||||
window.location = pyroutes.url('pullrequest_show', params) | ||||
} | ||||
return false; | ||||
}; | ||||
this.toggleVersionView = function (elem) { | ||||
if (this.$showVersionDiff.is(':visible')) { | ||||
$('.version-pr').hide(); | ||||
this.$showVersionDiff.hide(); | ||||
$(elem).html($(elem).data('toggleOn')) | ||||
} else { | ||||
$('.version-pr').show(); | ||||
this.$showVersionDiff.show(); | ||||
$(elem).html($(elem).data('toggleOff')) | ||||
} | ||||
return false | ||||
r4136 | }; | |||
r4101 | }; | |||
r4485 | window.UpdatePrController = function () { | |||
r4101 | var self = this; | |||
this.$updateCommits = $('#update_commits'); | ||||
this.$updateCommitsSwitcher = $('#update_commits_switcher'); | ||||
this.lockUpdateButton = function (label) { | ||||
self.$updateCommits.attr('disabled', 'disabled'); | ||||
self.$updateCommitsSwitcher.attr('disabled', 'disabled'); | ||||
self.$updateCommits.addClass('disabled'); | ||||
self.$updateCommitsSwitcher.addClass('disabled'); | ||||
self.$updateCommits.removeClass('btn-primary'); | ||||
self.$updateCommitsSwitcher.removeClass('btn-primary'); | ||||
self.$updateCommits.text(_gettext(label)); | ||||
}; | ||||
this.isUpdateLocked = function () { | ||||
return self.$updateCommits.attr('disabled') !== undefined; | ||||
}; | ||||
this.updateCommits = function (curNode) { | ||||
if (self.isUpdateLocked()) { | ||||
return | ||||
} | ||||
self.lockUpdateButton(_gettext('Updating...')); | ||||
updateCommits( | ||||
templateContext.repo_name, | ||||
templateContext.pull_request_data.pull_request_id); | ||||
}; | ||||
this.forceUpdateCommits = function () { | ||||
if (self.isUpdateLocked()) { | ||||
return | ||||
} | ||||
self.lockUpdateButton(_gettext('Force updating...')); | ||||
var force = true; | ||||
updateCommits( | ||||
templateContext.repo_name, | ||||
templateContext.pull_request_data.pull_request_id, force); | ||||
}; | ||||
r4485 | }; | |||
/** | ||||
* 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); | ||||
}; | ||||