##// END OF EJS Templates
pull-requests: fixed source/target in PR creation
milka -
r4584:2f0f671d stable
parent child Browse files
Show More
@@ -1,1170 +1,1170 b''
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19
19
20 var prButtonLockChecks = {
20 var prButtonLockChecks = {
21 'compare': false,
21 'compare': false,
22 'reviewers': false
22 'reviewers': false
23 };
23 };
24
24
25 /**
25 /**
26 * lock button until all checks and loads are made. E.g reviewer calculation
26 * lock button until all checks and loads are made. E.g reviewer calculation
27 * should prevent from submitting a PR
27 * should prevent from submitting a PR
28 * @param lockEnabled
28 * @param lockEnabled
29 * @param msg
29 * @param msg
30 * @param scope
30 * @param scope
31 */
31 */
32 var prButtonLock = function(lockEnabled, msg, scope) {
32 var prButtonLock = function(lockEnabled, msg, scope) {
33 scope = scope || 'all';
33 scope = scope || 'all';
34 if (scope == 'all'){
34 if (scope == 'all'){
35 prButtonLockChecks['compare'] = !lockEnabled;
35 prButtonLockChecks['compare'] = !lockEnabled;
36 prButtonLockChecks['reviewers'] = !lockEnabled;
36 prButtonLockChecks['reviewers'] = !lockEnabled;
37 } else if (scope == 'compare') {
37 } else if (scope == 'compare') {
38 prButtonLockChecks['compare'] = !lockEnabled;
38 prButtonLockChecks['compare'] = !lockEnabled;
39 } else if (scope == 'reviewers'){
39 } else if (scope == 'reviewers'){
40 prButtonLockChecks['reviewers'] = !lockEnabled;
40 prButtonLockChecks['reviewers'] = !lockEnabled;
41 }
41 }
42 var checksMeet = prButtonLockChecks.compare && prButtonLockChecks.reviewers;
42 var checksMeet = prButtonLockChecks.compare && prButtonLockChecks.reviewers;
43 if (lockEnabled) {
43 if (lockEnabled) {
44 $('#pr_submit').attr('disabled', 'disabled');
44 $('#pr_submit').attr('disabled', 'disabled');
45 }
45 }
46 else if (checksMeet) {
46 else if (checksMeet) {
47 $('#pr_submit').removeAttr('disabled');
47 $('#pr_submit').removeAttr('disabled');
48 }
48 }
49
49
50 if (msg) {
50 if (msg) {
51 $('#pr_open_message').html(msg);
51 $('#pr_open_message').html(msg);
52 }
52 }
53 };
53 };
54
54
55
55
56 /**
56 /**
57 Generate Title and Description for a PullRequest.
57 Generate Title and Description for a PullRequest.
58 In case of 1 commits, the title and description is that one commit
58 In case of 1 commits, the title and description is that one commit
59 in case of multiple commits, we iterate on them with max N number of commits,
59 in case of multiple commits, we iterate on them with max N number of commits,
60 and build description in a form
60 and build description in a form
61 - commitN
61 - commitN
62 - commitN+1
62 - commitN+1
63 ...
63 ...
64
64
65 Title is then constructed from branch names, or other references,
65 Title is then constructed from branch names, or other references,
66 replacing '-' and '_' into spaces
66 replacing '-' and '_' into spaces
67
67
68 * @param sourceRef
68 * @param sourceRef
69 * @param elements
69 * @param elements
70 * @param limit
70 * @param limit
71 * @returns {*[]}
71 * @returns {*[]}
72 */
72 */
73 var getTitleAndDescription = function(sourceRefType, sourceRef, elements, limit) {
73 var getTitleAndDescription = function(sourceRefType, sourceRef, elements, limit) {
74 var title = '';
74 var title = '';
75 var desc = '';
75 var desc = '';
76
76
77 $.each($(elements).get().reverse().slice(0, limit), function(idx, value) {
77 $.each($(elements).get().reverse().slice(0, limit), function(idx, value) {
78 var rawMessage = value['message'];
78 var rawMessage = value['message'];
79 desc += '- ' + rawMessage.split('\n')[0].replace(/\n+$/, "") + '\n';
79 desc += '- ' + rawMessage.split('\n')[0].replace(/\n+$/, "") + '\n';
80 });
80 });
81 // only 1 commit, use commit message as title
81 // only 1 commit, use commit message as title
82 if (elements.length === 1) {
82 if (elements.length === 1) {
83 var rawMessage = elements[0]['message'];
83 var rawMessage = elements[0]['message'];
84 title = rawMessage.split('\n')[0];
84 title = rawMessage.split('\n')[0];
85 }
85 }
86 else {
86 else {
87 // use reference name
87 // use reference name
88 var normalizedRef = sourceRef.replace(/-/g, ' ').replace(/_/g, ' ').capitalizeFirstLetter()
88 var normalizedRef = sourceRef.replace(/-/g, ' ').replace(/_/g, ' ').capitalizeFirstLetter()
89 var refType = sourceRefType;
89 var refType = sourceRefType;
90 title = 'Changes from {0}: {1}'.format(refType, normalizedRef);
90 title = 'Changes from {0}: {1}'.format(refType, normalizedRef);
91 }
91 }
92
92
93 return [title, desc]
93 return [title, desc]
94 };
94 };
95
95
96
96
97 window.ReviewersController = function () {
97 window.ReviewersController = function () {
98 var self = this;
98 var self = this;
99 this.$loadingIndicator = $('.calculate-reviewers');
99 this.$loadingIndicator = $('.calculate-reviewers');
100 this.$reviewRulesContainer = $('#review_rules');
100 this.$reviewRulesContainer = $('#review_rules');
101 this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules');
101 this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules');
102 this.$userRule = $('.pr-user-rule-container');
102 this.$userRule = $('.pr-user-rule-container');
103 this.$reviewMembers = $('#review_members');
103 this.$reviewMembers = $('#review_members');
104 this.$observerMembers = $('#observer_members');
104 this.$observerMembers = $('#observer_members');
105
105
106 this.currentRequest = null;
106 this.currentRequest = null;
107 this.diffData = null;
107 this.diffData = null;
108 this.enabledRules = [];
108 this.enabledRules = [];
109 // sync with db.py entries
109 // sync with db.py entries
110 this.ROLE_REVIEWER = 'reviewer';
110 this.ROLE_REVIEWER = 'reviewer';
111 this.ROLE_OBSERVER = 'observer'
111 this.ROLE_OBSERVER = 'observer'
112
112
113 //dummy handler, we might register our own later
113 //dummy handler, we might register our own later
114 this.diffDataHandler = function (data) {};
114 this.diffDataHandler = function (data) {};
115
115
116 this.defaultForbidUsers = function () {
116 this.defaultForbidUsers = function () {
117 return [
117 return [
118 {
118 {
119 'username': 'default',
119 'username': 'default',
120 'user_id': templateContext.default_user.user_id
120 'user_id': templateContext.default_user.user_id
121 }
121 }
122 ];
122 ];
123 };
123 };
124
124
125 // init default forbidden users
125 // init default forbidden users
126 this.forbidUsers = this.defaultForbidUsers();
126 this.forbidUsers = this.defaultForbidUsers();
127
127
128 this.hideReviewRules = function () {
128 this.hideReviewRules = function () {
129 self.$reviewRulesContainer.hide();
129 self.$reviewRulesContainer.hide();
130 $(self.$userRule.selector).hide();
130 $(self.$userRule.selector).hide();
131 };
131 };
132
132
133 this.showReviewRules = function () {
133 this.showReviewRules = function () {
134 self.$reviewRulesContainer.show();
134 self.$reviewRulesContainer.show();
135 $(self.$userRule.selector).show();
135 $(self.$userRule.selector).show();
136 };
136 };
137
137
138 this.addRule = function (ruleText) {
138 this.addRule = function (ruleText) {
139 self.showReviewRules();
139 self.showReviewRules();
140 self.enabledRules.push(ruleText);
140 self.enabledRules.push(ruleText);
141 return '<div>- {0}</div>'.format(ruleText)
141 return '<div>- {0}</div>'.format(ruleText)
142 };
142 };
143
143
144 this.increaseCounter = function(role) {
144 this.increaseCounter = function(role) {
145 if (role === self.ROLE_REVIEWER) {
145 if (role === self.ROLE_REVIEWER) {
146 var $elem = $('#reviewers-cnt')
146 var $elem = $('#reviewers-cnt')
147 var cnt = parseInt($elem.data('count') || 0)
147 var cnt = parseInt($elem.data('count') || 0)
148 cnt +=1
148 cnt +=1
149 $elem.html(cnt);
149 $elem.html(cnt);
150 $elem.data('count', cnt);
150 $elem.data('count', cnt);
151 }
151 }
152 else if (role === self.ROLE_OBSERVER) {
152 else if (role === self.ROLE_OBSERVER) {
153 var $elem = $('#observers-cnt');
153 var $elem = $('#observers-cnt');
154 var cnt = parseInt($elem.data('count') || 0)
154 var cnt = parseInt($elem.data('count') || 0)
155 cnt +=1
155 cnt +=1
156 $elem.html(cnt);
156 $elem.html(cnt);
157 $elem.data('count', cnt);
157 $elem.data('count', cnt);
158 }
158 }
159 }
159 }
160
160
161 this.resetCounter = function () {
161 this.resetCounter = function () {
162 var $elem = $('#reviewers-cnt');
162 var $elem = $('#reviewers-cnt');
163
163
164 $elem.data('count', 0);
164 $elem.data('count', 0);
165 $elem.html(0);
165 $elem.html(0);
166
166
167 var $elem = $('#observers-cnt');
167 var $elem = $('#observers-cnt');
168
168
169 $elem.data('count', 0);
169 $elem.data('count', 0);
170 $elem.html(0);
170 $elem.html(0);
171 }
171 }
172
172
173 this.loadReviewRules = function (data) {
173 this.loadReviewRules = function (data) {
174 self.diffData = data;
174 self.diffData = data;
175
175
176 // reset forbidden Users
176 // reset forbidden Users
177 this.forbidUsers = self.defaultForbidUsers();
177 this.forbidUsers = self.defaultForbidUsers();
178
178
179 // reset state of review rules
179 // reset state of review rules
180 self.$rulesList.html('');
180 self.$rulesList.html('');
181
181
182 if (!data || data.rules === undefined || $.isEmptyObject(data.rules)) {
182 if (!data || data.rules === undefined || $.isEmptyObject(data.rules)) {
183 // default rule, case for older repo that don't have any rules stored
183 // default rule, case for older repo that don't have any rules stored
184 self.$rulesList.append(
184 self.$rulesList.append(
185 self.addRule(_gettext('All reviewers must vote.'))
185 self.addRule(_gettext('All reviewers must vote.'))
186 );
186 );
187 return self.forbidUsers
187 return self.forbidUsers
188 }
188 }
189
189
190 if (data.rules.forbid_adding_reviewers) {
190 if (data.rules.forbid_adding_reviewers) {
191 $('#add_reviewer_input').remove();
191 $('#add_reviewer_input').remove();
192 }
192 }
193
193
194 if (data.rules_data !== undefined && data.rules_data.forbidden_users !== undefined) {
194 if (data.rules_data !== undefined && data.rules_data.forbidden_users !== undefined) {
195 $.each(data.rules_data.forbidden_users, function(idx, val){
195 $.each(data.rules_data.forbidden_users, function(idx, val){
196 self.forbidUsers.push(val)
196 self.forbidUsers.push(val)
197 })
197 })
198 }
198 }
199
199
200 if (data.rules_humanized !== undefined && data.rules_humanized.length > 0) {
200 if (data.rules_humanized !== undefined && data.rules_humanized.length > 0) {
201 $.each(data.rules_humanized, function(idx, val) {
201 $.each(data.rules_humanized, function(idx, val) {
202 self.$rulesList.append(
202 self.$rulesList.append(
203 self.addRule(val)
203 self.addRule(val)
204 )
204 )
205 })
205 })
206 } else {
206 } else {
207 // we don't have any rules set, so we inform users about it
207 // we don't have any rules set, so we inform users about it
208 self.$rulesList.append(
208 self.$rulesList.append(
209 self.addRule(_gettext('No additional review rules set.'))
209 self.addRule(_gettext('No additional review rules set.'))
210 )
210 )
211 }
211 }
212
212
213 return self.forbidUsers
213 return self.forbidUsers
214 };
214 };
215
215
216 this.emptyTables = function () {
216 this.emptyTables = function () {
217 self.emptyReviewersTable();
217 self.emptyReviewersTable();
218 self.emptyObserversTable();
218 self.emptyObserversTable();
219
219
220 // Also reset counters.
220 // Also reset counters.
221 self.resetCounter();
221 self.resetCounter();
222 }
222 }
223
223
224 this.emptyReviewersTable = function (withText) {
224 this.emptyReviewersTable = function (withText) {
225 self.$reviewMembers.empty();
225 self.$reviewMembers.empty();
226 if (withText !== undefined) {
226 if (withText !== undefined) {
227 self.$reviewMembers.html(withText)
227 self.$reviewMembers.html(withText)
228 }
228 }
229 };
229 };
230
230
231 this.emptyObserversTable = function (withText) {
231 this.emptyObserversTable = function (withText) {
232 self.$observerMembers.empty();
232 self.$observerMembers.empty();
233 if (withText !== undefined) {
233 if (withText !== undefined) {
234 self.$observerMembers.html(withText)
234 self.$observerMembers.html(withText)
235 }
235 }
236 }
236 }
237
237
238 this.loadDefaultReviewers = function (sourceRepo, sourceRef, targetRepo, targetRef) {
238 this.loadDefaultReviewers = function (sourceRepo, sourceRef, targetRepo, targetRef) {
239
239
240 if (self.currentRequest) {
240 if (self.currentRequest) {
241 // make sure we cleanup old running requests before triggering this again
241 // make sure we cleanup old running requests before triggering this again
242 self.currentRequest.abort();
242 self.currentRequest.abort();
243 }
243 }
244
244
245 self.$loadingIndicator.show();
245 self.$loadingIndicator.show();
246
246
247 // reset reviewer/observe members
247 // reset reviewer/observe members
248 self.emptyTables();
248 self.emptyTables();
249
249
250 prButtonLock(true, null, 'reviewers');
250 prButtonLock(true, null, 'reviewers');
251 $('#user').hide(); // hide user autocomplete before load
251 $('#user').hide(); // hide user autocomplete before load
252 $('#observer').hide(); //hide observer autocomplete before load
252 $('#observer').hide(); //hide observer autocomplete before load
253
253
254 // lock PR button, so we cannot send PR before it's calculated
254 // lock PR button, so we cannot send PR before it's calculated
255 prButtonLock(true, _gettext('Loading diff ...'), 'compare');
255 prButtonLock(true, _gettext('Loading diff ...'), 'compare');
256
256
257 if (sourceRef.length !== 3 || targetRef.length !== 3) {
257 if (sourceRef.length !== 3 || targetRef.length !== 3) {
258 // don't load defaults in case we're missing some refs...
258 // don't load defaults in case we're missing some refs...
259 self.$loadingIndicator.hide();
259 self.$loadingIndicator.hide();
260 return
260 return
261 }
261 }
262
262
263 var url = pyroutes.url('repo_default_reviewers_data',
263 var url = pyroutes.url('repo_default_reviewers_data',
264 {
264 {
265 'repo_name': templateContext.repo_name,
265 'repo_name': templateContext.repo_name,
266 'source_repo': sourceRepo,
266 'source_repo': sourceRepo,
267 'source_ref_type': sourceRef[0],
267 'source_ref_type': sourceRef[0],
268 'source_ref_name': sourceRef[1],
268 'source_ref_name': sourceRef[1],
269 'source_ref': sourceRef[2],
269 'source_ref': sourceRef[2],
270 'target_repo': targetRepo,
270 'target_repo': targetRepo,
271 'target_ref': targetRef[2],
271 'target_ref': targetRef[2],
272 'target_ref_type': sourceRef[0],
272 'target_ref_type': targetRef[0],
273 'target_ref_name': sourceRef[1]
273 'target_ref_name': targetRef[1]
274 });
274 });
275
275
276 self.currentRequest = $.ajax({
276 self.currentRequest = $.ajax({
277 url: url,
277 url: url,
278 headers: {'X-PARTIAL-XHR': true},
278 headers: {'X-PARTIAL-XHR': true},
279 type: 'GET',
279 type: 'GET',
280 success: function (data) {
280 success: function (data) {
281
281
282 self.currentRequest = null;
282 self.currentRequest = null;
283
283
284 // review rules
284 // review rules
285 self.loadReviewRules(data);
285 self.loadReviewRules(data);
286 var diffHandled = self.handleDiffData(data["diff_info"]);
286 var diffHandled = self.handleDiffData(data["diff_info"]);
287 if (diffHandled === false) {
287 if (diffHandled === false) {
288 return
288 return
289 }
289 }
290
290
291 for (var i = 0; i < data.reviewers.length; i++) {
291 for (var i = 0; i < data.reviewers.length; i++) {
292 var reviewer = data.reviewers[i];
292 var reviewer = data.reviewers[i];
293 // load reviewer rules from the repo data
293 // load reviewer rules from the repo data
294 self.addMember(reviewer, reviewer.reasons, reviewer.mandatory, reviewer.role);
294 self.addMember(reviewer, reviewer.reasons, reviewer.mandatory, reviewer.role);
295 }
295 }
296
296
297
297
298 self.$loadingIndicator.hide();
298 self.$loadingIndicator.hide();
299 prButtonLock(false, null, 'reviewers');
299 prButtonLock(false, null, 'reviewers');
300
300
301 $('#user').show(); // show user autocomplete before load
301 $('#user').show(); // show user autocomplete before load
302 $('#observer').show(); // show observer autocomplete before load
302 $('#observer').show(); // show observer autocomplete before load
303
303
304 var commitElements = data["diff_info"]['commits'];
304 var commitElements = data["diff_info"]['commits'];
305
305
306 if (commitElements.length === 0) {
306 if (commitElements.length === 0) {
307 var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
307 var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
308 _gettext('There are no commits to merge.'));
308 _gettext('There are no commits to merge.'));
309 prButtonLock(true, noCommitsMsg, 'all');
309 prButtonLock(true, noCommitsMsg, 'all');
310
310
311 } else {
311 } else {
312 // un-lock PR button, so we cannot send PR before it's calculated
312 // un-lock PR button, so we cannot send PR before it's calculated
313 prButtonLock(false, null, 'compare');
313 prButtonLock(false, null, 'compare');
314 }
314 }
315
315
316 },
316 },
317 error: function (jqXHR, textStatus, errorThrown) {
317 error: function (jqXHR, textStatus, errorThrown) {
318 var prefix = "Loading diff and reviewers/observers failed\n"
318 var prefix = "Loading diff and reviewers/observers failed\n"
319 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
319 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
320 ajaxErrorSwal(message);
320 ajaxErrorSwal(message);
321 }
321 }
322 });
322 });
323
323
324 };
324 };
325
325
326 // check those, refactor
326 // check those, refactor
327 this.removeMember = function (reviewer_id, mark_delete) {
327 this.removeMember = function (reviewer_id, mark_delete) {
328 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
328 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
329
329
330 if (typeof (mark_delete) === undefined) {
330 if (typeof (mark_delete) === undefined) {
331 mark_delete = false;
331 mark_delete = false;
332 }
332 }
333
333
334 if (mark_delete === true) {
334 if (mark_delete === true) {
335 if (reviewer) {
335 if (reviewer) {
336 // now delete the input
336 // now delete the input
337 $('#reviewer_{0} input'.format(reviewer_id)).remove();
337 $('#reviewer_{0} input'.format(reviewer_id)).remove();
338 $('#reviewer_{0}_rules input'.format(reviewer_id)).remove();
338 $('#reviewer_{0}_rules input'.format(reviewer_id)).remove();
339 // mark as to-delete
339 // mark as to-delete
340 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
340 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
341 obj.addClass('to-delete');
341 obj.addClass('to-delete');
342 obj.css({"text-decoration": "line-through", "opacity": 0.5});
342 obj.css({"text-decoration": "line-through", "opacity": 0.5});
343 }
343 }
344 } else {
344 } else {
345 $('#reviewer_{0}'.format(reviewer_id)).remove();
345 $('#reviewer_{0}'.format(reviewer_id)).remove();
346 }
346 }
347 };
347 };
348
348
349 this.addMember = function (reviewer_obj, reasons, mandatory, role) {
349 this.addMember = function (reviewer_obj, reasons, mandatory, role) {
350
350
351 var id = reviewer_obj.user_id;
351 var id = reviewer_obj.user_id;
352 var username = reviewer_obj.username;
352 var username = reviewer_obj.username;
353
353
354 reasons = reasons || [];
354 reasons = reasons || [];
355 mandatory = mandatory || false;
355 mandatory = mandatory || false;
356 role = role || self.ROLE_REVIEWER
356 role = role || self.ROLE_REVIEWER
357
357
358 // register current set IDS to check if we don't have this ID already in
358 // register current set IDS to check if we don't have this ID already in
359 // and prevent duplicates
359 // and prevent duplicates
360 var currentIds = [];
360 var currentIds = [];
361
361
362 $.each($('.reviewer_entry'), function (index, value) {
362 $.each($('.reviewer_entry'), function (index, value) {
363 currentIds.push($(value).data('reviewerUserId'))
363 currentIds.push($(value).data('reviewerUserId'))
364 })
364 })
365
365
366 var userAllowedReview = function (userId) {
366 var userAllowedReview = function (userId) {
367 var allowed = true;
367 var allowed = true;
368 $.each(self.forbidUsers, function (index, member_data) {
368 $.each(self.forbidUsers, function (index, member_data) {
369 if (parseInt(userId) === member_data['user_id']) {
369 if (parseInt(userId) === member_data['user_id']) {
370 allowed = false;
370 allowed = false;
371 return false // breaks the loop
371 return false // breaks the loop
372 }
372 }
373 });
373 });
374 return allowed
374 return allowed
375 };
375 };
376
376
377 var userAllowed = userAllowedReview(id);
377 var userAllowed = userAllowedReview(id);
378
378
379 if (!userAllowed) {
379 if (!userAllowed) {
380 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
380 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
381 } else {
381 } else {
382 // only add if it's not there
382 // only add if it's not there
383 var alreadyReviewer = currentIds.indexOf(id) != -1;
383 var alreadyReviewer = currentIds.indexOf(id) != -1;
384
384
385 if (alreadyReviewer) {
385 if (alreadyReviewer) {
386 alert(_gettext('User `{0}` already in reviewers/observers').format(username));
386 alert(_gettext('User `{0}` already in reviewers/observers').format(username));
387 } else {
387 } else {
388
388
389 var reviewerEntry = renderTemplate('reviewMemberEntry', {
389 var reviewerEntry = renderTemplate('reviewMemberEntry', {
390 'member': reviewer_obj,
390 'member': reviewer_obj,
391 'mandatory': mandatory,
391 'mandatory': mandatory,
392 'role': role,
392 'role': role,
393 'reasons': reasons,
393 'reasons': reasons,
394 'allowed_to_update': true,
394 'allowed_to_update': true,
395 'review_status': 'not_reviewed',
395 'review_status': 'not_reviewed',
396 'review_status_label': _gettext('Not Reviewed'),
396 'review_status_label': _gettext('Not Reviewed'),
397 'user_group': reviewer_obj.user_group,
397 'user_group': reviewer_obj.user_group,
398 'create': true,
398 'create': true,
399 'rule_show': true,
399 'rule_show': true,
400 })
400 })
401
401
402 if (role === self.ROLE_REVIEWER) {
402 if (role === self.ROLE_REVIEWER) {
403 $(self.$reviewMembers.selector).append(reviewerEntry);
403 $(self.$reviewMembers.selector).append(reviewerEntry);
404 self.increaseCounter(self.ROLE_REVIEWER);
404 self.increaseCounter(self.ROLE_REVIEWER);
405 $('#reviewer-empty-msg').remove()
405 $('#reviewer-empty-msg').remove()
406 }
406 }
407 else if (role === self.ROLE_OBSERVER) {
407 else if (role === self.ROLE_OBSERVER) {
408 $(self.$observerMembers.selector).append(reviewerEntry);
408 $(self.$observerMembers.selector).append(reviewerEntry);
409 self.increaseCounter(self.ROLE_OBSERVER);
409 self.increaseCounter(self.ROLE_OBSERVER);
410 $('#observer-empty-msg').remove();
410 $('#observer-empty-msg').remove();
411 }
411 }
412
412
413 tooltipActivate();
413 tooltipActivate();
414 }
414 }
415 }
415 }
416
416
417 };
417 };
418
418
419 this.updateReviewers = function (repo_name, pull_request_id, role) {
419 this.updateReviewers = function (repo_name, pull_request_id, role) {
420 if (role === 'reviewer') {
420 if (role === 'reviewer') {
421 var postData = $('#reviewers input').serialize();
421 var postData = $('#reviewers input').serialize();
422 _updatePullRequest(repo_name, pull_request_id, postData);
422 _updatePullRequest(repo_name, pull_request_id, postData);
423 } else if (role === 'observer') {
423 } else if (role === 'observer') {
424 var postData = $('#observers input').serialize();
424 var postData = $('#observers input').serialize();
425 _updatePullRequest(repo_name, pull_request_id, postData);
425 _updatePullRequest(repo_name, pull_request_id, postData);
426 }
426 }
427 };
427 };
428
428
429 this.handleDiffData = function (data) {
429 this.handleDiffData = function (data) {
430 return self.diffDataHandler(data)
430 return self.diffDataHandler(data)
431 }
431 }
432 };
432 };
433
433
434
434
435 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
435 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
436 var url = pyroutes.url(
436 var url = pyroutes.url(
437 'pullrequest_update',
437 'pullrequest_update',
438 {"repo_name": repo_name, "pull_request_id": pull_request_id});
438 {"repo_name": repo_name, "pull_request_id": pull_request_id});
439 if (typeof postData === 'string' ) {
439 if (typeof postData === 'string' ) {
440 postData += '&csrf_token=' + CSRF_TOKEN;
440 postData += '&csrf_token=' + CSRF_TOKEN;
441 } else {
441 } else {
442 postData.csrf_token = CSRF_TOKEN;
442 postData.csrf_token = CSRF_TOKEN;
443 }
443 }
444
444
445 var success = function(o) {
445 var success = function(o) {
446 var redirectUrl = o['redirect_url'];
446 var redirectUrl = o['redirect_url'];
447 if (redirectUrl !== undefined && redirectUrl !== null && redirectUrl !== '') {
447 if (redirectUrl !== undefined && redirectUrl !== null && redirectUrl !== '') {
448 window.location = redirectUrl;
448 window.location = redirectUrl;
449 } else {
449 } else {
450 window.location.reload();
450 window.location.reload();
451 }
451 }
452 };
452 };
453
453
454 ajaxPOST(url, postData, success);
454 ajaxPOST(url, postData, success);
455 };
455 };
456
456
457 /**
457 /**
458 * PULL REQUEST update commits
458 * PULL REQUEST update commits
459 */
459 */
460 var updateCommits = function(repo_name, pull_request_id, force) {
460 var updateCommits = function(repo_name, pull_request_id, force) {
461 var postData = {
461 var postData = {
462 'update_commits': true
462 'update_commits': true
463 };
463 };
464 if (force !== undefined && force === true) {
464 if (force !== undefined && force === true) {
465 postData['force_refresh'] = true
465 postData['force_refresh'] = true
466 }
466 }
467 _updatePullRequest(repo_name, pull_request_id, postData);
467 _updatePullRequest(repo_name, pull_request_id, postData);
468 };
468 };
469
469
470
470
471 /**
471 /**
472 * PULL REQUEST edit info
472 * PULL REQUEST edit info
473 */
473 */
474 var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) {
474 var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) {
475 var url = pyroutes.url(
475 var url = pyroutes.url(
476 'pullrequest_update',
476 'pullrequest_update',
477 {"repo_name": repo_name, "pull_request_id": pull_request_id});
477 {"repo_name": repo_name, "pull_request_id": pull_request_id});
478
478
479 var postData = {
479 var postData = {
480 'title': title,
480 'title': title,
481 'description': description,
481 'description': description,
482 'description_renderer': renderer,
482 'description_renderer': renderer,
483 'edit_pull_request': true,
483 'edit_pull_request': true,
484 'csrf_token': CSRF_TOKEN
484 'csrf_token': CSRF_TOKEN
485 };
485 };
486 var success = function(o) {
486 var success = function(o) {
487 window.location.reload();
487 window.location.reload();
488 };
488 };
489 ajaxPOST(url, postData, success);
489 ajaxPOST(url, postData, success);
490 };
490 };
491
491
492
492
493 /**
493 /**
494 * autocomplete handler for reviewers/observers
494 * autocomplete handler for reviewers/observers
495 */
495 */
496 var autoCompleteHandler = function (inputId, controller, role) {
496 var autoCompleteHandler = function (inputId, controller, role) {
497
497
498 return function (element, data) {
498 return function (element, data) {
499 var mandatory = false;
499 var mandatory = false;
500 var reasons = [_gettext('added manually by "{0}"').format(
500 var reasons = [_gettext('added manually by "{0}"').format(
501 templateContext.rhodecode_user.username)];
501 templateContext.rhodecode_user.username)];
502
502
503 // add whole user groups
503 // add whole user groups
504 if (data.value_type == 'user_group') {
504 if (data.value_type == 'user_group') {
505 reasons.push(_gettext('member of "{0}"').format(data.value_display));
505 reasons.push(_gettext('member of "{0}"').format(data.value_display));
506
506
507 $.each(data.members, function (index, member_data) {
507 $.each(data.members, function (index, member_data) {
508 var reviewer = member_data;
508 var reviewer = member_data;
509 reviewer['user_id'] = member_data['id'];
509 reviewer['user_id'] = member_data['id'];
510 reviewer['gravatar_link'] = member_data['icon_link'];
510 reviewer['gravatar_link'] = member_data['icon_link'];
511 reviewer['user_link'] = member_data['profile_link'];
511 reviewer['user_link'] = member_data['profile_link'];
512 reviewer['rules'] = [];
512 reviewer['rules'] = [];
513 controller.addMember(reviewer, reasons, mandatory, role);
513 controller.addMember(reviewer, reasons, mandatory, role);
514 })
514 })
515 }
515 }
516 // add single user
516 // add single user
517 else {
517 else {
518 var reviewer = data;
518 var reviewer = data;
519 reviewer['user_id'] = data['id'];
519 reviewer['user_id'] = data['id'];
520 reviewer['gravatar_link'] = data['icon_link'];
520 reviewer['gravatar_link'] = data['icon_link'];
521 reviewer['user_link'] = data['profile_link'];
521 reviewer['user_link'] = data['profile_link'];
522 reviewer['rules'] = [];
522 reviewer['rules'] = [];
523 controller.addMember(reviewer, reasons, mandatory, role);
523 controller.addMember(reviewer, reasons, mandatory, role);
524 }
524 }
525
525
526 $(inputId).val('');
526 $(inputId).val('');
527 }
527 }
528 }
528 }
529
529
530 /**
530 /**
531 * Reviewer autocomplete
531 * Reviewer autocomplete
532 */
532 */
533 var ReviewerAutoComplete = function (inputId, controller) {
533 var ReviewerAutoComplete = function (inputId, controller) {
534 var self = this;
534 var self = this;
535 self.controller = controller;
535 self.controller = controller;
536 self.inputId = inputId;
536 self.inputId = inputId;
537 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_REVIEWER);
537 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_REVIEWER);
538
538
539 $(inputId).autocomplete({
539 $(inputId).autocomplete({
540 serviceUrl: pyroutes.url('user_autocomplete_data'),
540 serviceUrl: pyroutes.url('user_autocomplete_data'),
541 minChars: 2,
541 minChars: 2,
542 maxHeight: 400,
542 maxHeight: 400,
543 deferRequestBy: 300, //miliseconds
543 deferRequestBy: 300, //miliseconds
544 showNoSuggestionNotice: true,
544 showNoSuggestionNotice: true,
545 tabDisabled: true,
545 tabDisabled: true,
546 autoSelectFirst: true,
546 autoSelectFirst: true,
547 params: {
547 params: {
548 user_id: templateContext.rhodecode_user.user_id,
548 user_id: templateContext.rhodecode_user.user_id,
549 user_groups: true,
549 user_groups: true,
550 user_groups_expand: true,
550 user_groups_expand: true,
551 skip_default_user: true
551 skip_default_user: true
552 },
552 },
553 formatResult: autocompleteFormatResult,
553 formatResult: autocompleteFormatResult,
554 lookupFilter: autocompleteFilterResult,
554 lookupFilter: autocompleteFilterResult,
555 onSelect: handler
555 onSelect: handler
556 });
556 });
557 };
557 };
558
558
559 /**
559 /**
560 * Observers autocomplete
560 * Observers autocomplete
561 */
561 */
562 var ObserverAutoComplete = function(inputId, controller) {
562 var ObserverAutoComplete = function(inputId, controller) {
563 var self = this;
563 var self = this;
564 self.controller = controller;
564 self.controller = controller;
565 self.inputId = inputId;
565 self.inputId = inputId;
566 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_OBSERVER);
566 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_OBSERVER);
567
567
568 $(inputId).autocomplete({
568 $(inputId).autocomplete({
569 serviceUrl: pyroutes.url('user_autocomplete_data'),
569 serviceUrl: pyroutes.url('user_autocomplete_data'),
570 minChars: 2,
570 minChars: 2,
571 maxHeight: 400,
571 maxHeight: 400,
572 deferRequestBy: 300, //miliseconds
572 deferRequestBy: 300, //miliseconds
573 showNoSuggestionNotice: true,
573 showNoSuggestionNotice: true,
574 tabDisabled: true,
574 tabDisabled: true,
575 autoSelectFirst: true,
575 autoSelectFirst: true,
576 params: {
576 params: {
577 user_id: templateContext.rhodecode_user.user_id,
577 user_id: templateContext.rhodecode_user.user_id,
578 user_groups: true,
578 user_groups: true,
579 user_groups_expand: true,
579 user_groups_expand: true,
580 skip_default_user: true
580 skip_default_user: true
581 },
581 },
582 formatResult: autocompleteFormatResult,
582 formatResult: autocompleteFormatResult,
583 lookupFilter: autocompleteFilterResult,
583 lookupFilter: autocompleteFilterResult,
584 onSelect: handler
584 onSelect: handler
585 });
585 });
586 }
586 }
587
587
588
588
589 window.VersionController = function () {
589 window.VersionController = function () {
590 var self = this;
590 var self = this;
591 this.$verSource = $('input[name=ver_source]');
591 this.$verSource = $('input[name=ver_source]');
592 this.$verTarget = $('input[name=ver_target]');
592 this.$verTarget = $('input[name=ver_target]');
593 this.$showVersionDiff = $('#show-version-diff');
593 this.$showVersionDiff = $('#show-version-diff');
594
594
595 this.adjustRadioSelectors = function (curNode) {
595 this.adjustRadioSelectors = function (curNode) {
596 var getVal = function (item) {
596 var getVal = function (item) {
597 if (item === 'latest') {
597 if (item === 'latest') {
598 return Number.MAX_SAFE_INTEGER
598 return Number.MAX_SAFE_INTEGER
599 }
599 }
600 else {
600 else {
601 return parseInt(item)
601 return parseInt(item)
602 }
602 }
603 };
603 };
604
604
605 var curVal = getVal($(curNode).val());
605 var curVal = getVal($(curNode).val());
606 var cleared = false;
606 var cleared = false;
607
607
608 $.each(self.$verSource, function (index, value) {
608 $.each(self.$verSource, function (index, value) {
609 var elVal = getVal($(value).val());
609 var elVal = getVal($(value).val());
610
610
611 if (elVal > curVal) {
611 if (elVal > curVal) {
612 if ($(value).is(':checked')) {
612 if ($(value).is(':checked')) {
613 cleared = true;
613 cleared = true;
614 }
614 }
615 $(value).attr('disabled', 'disabled');
615 $(value).attr('disabled', 'disabled');
616 $(value).removeAttr('checked');
616 $(value).removeAttr('checked');
617 $(value).css({'opacity': 0.1});
617 $(value).css({'opacity': 0.1});
618 }
618 }
619 else {
619 else {
620 $(value).css({'opacity': 1});
620 $(value).css({'opacity': 1});
621 $(value).removeAttr('disabled');
621 $(value).removeAttr('disabled');
622 }
622 }
623 });
623 });
624
624
625 if (cleared) {
625 if (cleared) {
626 // if we unchecked an active, set the next one to same loc.
626 // if we unchecked an active, set the next one to same loc.
627 $(this.$verSource).filter('[value={0}]'.format(
627 $(this.$verSource).filter('[value={0}]'.format(
628 curVal)).attr('checked', 'checked');
628 curVal)).attr('checked', 'checked');
629 }
629 }
630
630
631 self.setLockAction(false,
631 self.setLockAction(false,
632 $(curNode).data('verPos'),
632 $(curNode).data('verPos'),
633 $(this.$verSource).filter(':checked').data('verPos')
633 $(this.$verSource).filter(':checked').data('verPos')
634 );
634 );
635 };
635 };
636
636
637
637
638 this.attachVersionListener = function () {
638 this.attachVersionListener = function () {
639 self.$verTarget.change(function (e) {
639 self.$verTarget.change(function (e) {
640 self.adjustRadioSelectors(this)
640 self.adjustRadioSelectors(this)
641 });
641 });
642 self.$verSource.change(function (e) {
642 self.$verSource.change(function (e) {
643 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
643 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
644 });
644 });
645 };
645 };
646
646
647 this.init = function () {
647 this.init = function () {
648
648
649 var curNode = self.$verTarget.filter(':checked');
649 var curNode = self.$verTarget.filter(':checked');
650 self.adjustRadioSelectors(curNode);
650 self.adjustRadioSelectors(curNode);
651 self.setLockAction(true);
651 self.setLockAction(true);
652 self.attachVersionListener();
652 self.attachVersionListener();
653
653
654 };
654 };
655
655
656 this.setLockAction = function (state, selectedVersion, otherVersion) {
656 this.setLockAction = function (state, selectedVersion, otherVersion) {
657 var $showVersionDiff = this.$showVersionDiff;
657 var $showVersionDiff = this.$showVersionDiff;
658
658
659 if (state) {
659 if (state) {
660 $showVersionDiff.attr('disabled', 'disabled');
660 $showVersionDiff.attr('disabled', 'disabled');
661 $showVersionDiff.addClass('disabled');
661 $showVersionDiff.addClass('disabled');
662 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
662 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
663 }
663 }
664 else {
664 else {
665 $showVersionDiff.removeAttr('disabled');
665 $showVersionDiff.removeAttr('disabled');
666 $showVersionDiff.removeClass('disabled');
666 $showVersionDiff.removeClass('disabled');
667
667
668 if (selectedVersion == otherVersion) {
668 if (selectedVersion == otherVersion) {
669 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
669 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
670 } else {
670 } else {
671 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
671 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
672 }
672 }
673 }
673 }
674
674
675 };
675 };
676
676
677 this.showVersionDiff = function () {
677 this.showVersionDiff = function () {
678 var target = self.$verTarget.filter(':checked');
678 var target = self.$verTarget.filter(':checked');
679 var source = self.$verSource.filter(':checked');
679 var source = self.$verSource.filter(':checked');
680
680
681 if (target.val() && source.val()) {
681 if (target.val() && source.val()) {
682 var params = {
682 var params = {
683 'pull_request_id': templateContext.pull_request_data.pull_request_id,
683 'pull_request_id': templateContext.pull_request_data.pull_request_id,
684 'repo_name': templateContext.repo_name,
684 'repo_name': templateContext.repo_name,
685 'version': target.val(),
685 'version': target.val(),
686 'from_version': source.val()
686 'from_version': source.val()
687 };
687 };
688 window.location = pyroutes.url('pullrequest_show', params)
688 window.location = pyroutes.url('pullrequest_show', params)
689 }
689 }
690
690
691 return false;
691 return false;
692 };
692 };
693
693
694 this.toggleVersionView = function (elem) {
694 this.toggleVersionView = function (elem) {
695
695
696 if (this.$showVersionDiff.is(':visible')) {
696 if (this.$showVersionDiff.is(':visible')) {
697 $('.version-pr').hide();
697 $('.version-pr').hide();
698 this.$showVersionDiff.hide();
698 this.$showVersionDiff.hide();
699 $(elem).html($(elem).data('toggleOn'))
699 $(elem).html($(elem).data('toggleOn'))
700 } else {
700 } else {
701 $('.version-pr').show();
701 $('.version-pr').show();
702 this.$showVersionDiff.show();
702 this.$showVersionDiff.show();
703 $(elem).html($(elem).data('toggleOff'))
703 $(elem).html($(elem).data('toggleOff'))
704 }
704 }
705
705
706 return false
706 return false
707 };
707 };
708
708
709 };
709 };
710
710
711
711
712 window.UpdatePrController = function () {
712 window.UpdatePrController = function () {
713 var self = this;
713 var self = this;
714 this.$updateCommits = $('#update_commits');
714 this.$updateCommits = $('#update_commits');
715 this.$updateCommitsSwitcher = $('#update_commits_switcher');
715 this.$updateCommitsSwitcher = $('#update_commits_switcher');
716
716
717 this.lockUpdateButton = function (label) {
717 this.lockUpdateButton = function (label) {
718 self.$updateCommits.attr('disabled', 'disabled');
718 self.$updateCommits.attr('disabled', 'disabled');
719 self.$updateCommitsSwitcher.attr('disabled', 'disabled');
719 self.$updateCommitsSwitcher.attr('disabled', 'disabled');
720
720
721 self.$updateCommits.addClass('disabled');
721 self.$updateCommits.addClass('disabled');
722 self.$updateCommitsSwitcher.addClass('disabled');
722 self.$updateCommitsSwitcher.addClass('disabled');
723
723
724 self.$updateCommits.removeClass('btn-primary');
724 self.$updateCommits.removeClass('btn-primary');
725 self.$updateCommitsSwitcher.removeClass('btn-primary');
725 self.$updateCommitsSwitcher.removeClass('btn-primary');
726
726
727 self.$updateCommits.text(_gettext(label));
727 self.$updateCommits.text(_gettext(label));
728 };
728 };
729
729
730 this.isUpdateLocked = function () {
730 this.isUpdateLocked = function () {
731 return self.$updateCommits.attr('disabled') !== undefined;
731 return self.$updateCommits.attr('disabled') !== undefined;
732 };
732 };
733
733
734 this.updateCommits = function (curNode) {
734 this.updateCommits = function (curNode) {
735 if (self.isUpdateLocked()) {
735 if (self.isUpdateLocked()) {
736 return
736 return
737 }
737 }
738 self.lockUpdateButton(_gettext('Updating...'));
738 self.lockUpdateButton(_gettext('Updating...'));
739 updateCommits(
739 updateCommits(
740 templateContext.repo_name,
740 templateContext.repo_name,
741 templateContext.pull_request_data.pull_request_id);
741 templateContext.pull_request_data.pull_request_id);
742 };
742 };
743
743
744 this.forceUpdateCommits = function () {
744 this.forceUpdateCommits = function () {
745 if (self.isUpdateLocked()) {
745 if (self.isUpdateLocked()) {
746 return
746 return
747 }
747 }
748 self.lockUpdateButton(_gettext('Force updating...'));
748 self.lockUpdateButton(_gettext('Force updating...'));
749 var force = true;
749 var force = true;
750 updateCommits(
750 updateCommits(
751 templateContext.repo_name,
751 templateContext.repo_name,
752 templateContext.pull_request_data.pull_request_id, force);
752 templateContext.pull_request_data.pull_request_id, force);
753 };
753 };
754 };
754 };
755
755
756
756
757 /**
757 /**
758 * Reviewer display panel
758 * Reviewer display panel
759 */
759 */
760 window.ReviewersPanel = {
760 window.ReviewersPanel = {
761 editButton: null,
761 editButton: null,
762 closeButton: null,
762 closeButton: null,
763 addButton: null,
763 addButton: null,
764 removeButtons: null,
764 removeButtons: null,
765 reviewRules: null,
765 reviewRules: null,
766 setReviewers: null,
766 setReviewers: null,
767 controller: null,
767 controller: null,
768
768
769 setSelectors: function () {
769 setSelectors: function () {
770 var self = this;
770 var self = this;
771 self.editButton = $('#open_edit_reviewers');
771 self.editButton = $('#open_edit_reviewers');
772 self.closeButton =$('#close_edit_reviewers');
772 self.closeButton =$('#close_edit_reviewers');
773 self.addButton = $('#add_reviewer');
773 self.addButton = $('#add_reviewer');
774 self.removeButtons = $('.reviewer_member_remove,.reviewer_member_mandatory_remove');
774 self.removeButtons = $('.reviewer_member_remove,.reviewer_member_mandatory_remove');
775 },
775 },
776
776
777 init: function (controller, reviewRules, setReviewers) {
777 init: function (controller, reviewRules, setReviewers) {
778 var self = this;
778 var self = this;
779 self.setSelectors();
779 self.setSelectors();
780
780
781 self.controller = controller;
781 self.controller = controller;
782 self.reviewRules = reviewRules;
782 self.reviewRules = reviewRules;
783 self.setReviewers = setReviewers;
783 self.setReviewers = setReviewers;
784
784
785 self.editButton.on('click', function (e) {
785 self.editButton.on('click', function (e) {
786 self.edit();
786 self.edit();
787 });
787 });
788 self.closeButton.on('click', function (e) {
788 self.closeButton.on('click', function (e) {
789 self.close();
789 self.close();
790 self.renderReviewers();
790 self.renderReviewers();
791 });
791 });
792
792
793 self.renderReviewers();
793 self.renderReviewers();
794
794
795 },
795 },
796
796
797 renderReviewers: function () {
797 renderReviewers: function () {
798 var self = this;
798 var self = this;
799
799
800 if (self.setReviewers.reviewers === undefined) {
800 if (self.setReviewers.reviewers === undefined) {
801 return
801 return
802 }
802 }
803 if (self.setReviewers.reviewers.length === 0) {
803 if (self.setReviewers.reviewers.length === 0) {
804 self.controller.emptyReviewersTable('<tr id="reviewer-empty-msg"><td colspan="6">No reviewers</td></tr>');
804 self.controller.emptyReviewersTable('<tr id="reviewer-empty-msg"><td colspan="6">No reviewers</td></tr>');
805 return
805 return
806 }
806 }
807
807
808 self.controller.emptyReviewersTable();
808 self.controller.emptyReviewersTable();
809
809
810 $.each(self.setReviewers.reviewers, function (key, val) {
810 $.each(self.setReviewers.reviewers, function (key, val) {
811
811
812 var member = val;
812 var member = val;
813 if (member.role === self.controller.ROLE_REVIEWER) {
813 if (member.role === self.controller.ROLE_REVIEWER) {
814 var entry = renderTemplate('reviewMemberEntry', {
814 var entry = renderTemplate('reviewMemberEntry', {
815 'member': member,
815 'member': member,
816 'mandatory': member.mandatory,
816 'mandatory': member.mandatory,
817 'role': member.role,
817 'role': member.role,
818 'reasons': member.reasons,
818 'reasons': member.reasons,
819 'allowed_to_update': member.allowed_to_update,
819 'allowed_to_update': member.allowed_to_update,
820 'review_status': member.review_status,
820 'review_status': member.review_status,
821 'review_status_label': member.review_status_label,
821 'review_status_label': member.review_status_label,
822 'user_group': member.user_group,
822 'user_group': member.user_group,
823 'create': false
823 'create': false
824 });
824 });
825
825
826 $(self.controller.$reviewMembers.selector).append(entry)
826 $(self.controller.$reviewMembers.selector).append(entry)
827 }
827 }
828 });
828 });
829
829
830 tooltipActivate();
830 tooltipActivate();
831 },
831 },
832
832
833 edit: function (event) {
833 edit: function (event) {
834 var self = this;
834 var self = this;
835 self.editButton.hide();
835 self.editButton.hide();
836 self.closeButton.show();
836 self.closeButton.show();
837 self.addButton.show();
837 self.addButton.show();
838 $(self.removeButtons.selector).css('visibility', 'visible');
838 $(self.removeButtons.selector).css('visibility', 'visible');
839 // review rules
839 // review rules
840 self.controller.loadReviewRules(this.reviewRules);
840 self.controller.loadReviewRules(this.reviewRules);
841 },
841 },
842
842
843 close: function (event) {
843 close: function (event) {
844 var self = this;
844 var self = this;
845 this.editButton.show();
845 this.editButton.show();
846 this.closeButton.hide();
846 this.closeButton.hide();
847 this.addButton.hide();
847 this.addButton.hide();
848 $(this.removeButtons.selector).css('visibility', 'hidden');
848 $(this.removeButtons.selector).css('visibility', 'hidden');
849 // hide review rules
849 // hide review rules
850 self.controller.hideReviewRules();
850 self.controller.hideReviewRules();
851 }
851 }
852 };
852 };
853
853
854 /**
854 /**
855 * Reviewer display panel
855 * Reviewer display panel
856 */
856 */
857 window.ObserversPanel = {
857 window.ObserversPanel = {
858 editButton: null,
858 editButton: null,
859 closeButton: null,
859 closeButton: null,
860 addButton: null,
860 addButton: null,
861 removeButtons: null,
861 removeButtons: null,
862 reviewRules: null,
862 reviewRules: null,
863 setReviewers: null,
863 setReviewers: null,
864 controller: null,
864 controller: null,
865
865
866 setSelectors: function () {
866 setSelectors: function () {
867 var self = this;
867 var self = this;
868 self.editButton = $('#open_edit_observers');
868 self.editButton = $('#open_edit_observers');
869 self.closeButton =$('#close_edit_observers');
869 self.closeButton =$('#close_edit_observers');
870 self.addButton = $('#add_observer');
870 self.addButton = $('#add_observer');
871 self.removeButtons = $('.observer_member_remove,.observer_member_mandatory_remove');
871 self.removeButtons = $('.observer_member_remove,.observer_member_mandatory_remove');
872 },
872 },
873
873
874 init: function (controller, reviewRules, setReviewers) {
874 init: function (controller, reviewRules, setReviewers) {
875 var self = this;
875 var self = this;
876 self.setSelectors();
876 self.setSelectors();
877
877
878 self.controller = controller;
878 self.controller = controller;
879 self.reviewRules = reviewRules;
879 self.reviewRules = reviewRules;
880 self.setReviewers = setReviewers;
880 self.setReviewers = setReviewers;
881
881
882 self.editButton.on('click', function (e) {
882 self.editButton.on('click', function (e) {
883 self.edit();
883 self.edit();
884 });
884 });
885 self.closeButton.on('click', function (e) {
885 self.closeButton.on('click', function (e) {
886 self.close();
886 self.close();
887 self.renderObservers();
887 self.renderObservers();
888 });
888 });
889
889
890 self.renderObservers();
890 self.renderObservers();
891
891
892 },
892 },
893
893
894 renderObservers: function () {
894 renderObservers: function () {
895 var self = this;
895 var self = this;
896 if (self.setReviewers.observers === undefined) {
896 if (self.setReviewers.observers === undefined) {
897 return
897 return
898 }
898 }
899 if (self.setReviewers.observers.length === 0) {
899 if (self.setReviewers.observers.length === 0) {
900 self.controller.emptyObserversTable('<tr id="observer-empty-msg"><td colspan="6">No observers</td></tr>');
900 self.controller.emptyObserversTable('<tr id="observer-empty-msg"><td colspan="6">No observers</td></tr>');
901 return
901 return
902 }
902 }
903
903
904 self.controller.emptyObserversTable();
904 self.controller.emptyObserversTable();
905
905
906 $.each(self.setReviewers.observers, function (key, val) {
906 $.each(self.setReviewers.observers, function (key, val) {
907 var member = val;
907 var member = val;
908 if (member.role === self.controller.ROLE_OBSERVER) {
908 if (member.role === self.controller.ROLE_OBSERVER) {
909 var entry = renderTemplate('reviewMemberEntry', {
909 var entry = renderTemplate('reviewMemberEntry', {
910 'member': member,
910 'member': member,
911 'mandatory': member.mandatory,
911 'mandatory': member.mandatory,
912 'role': member.role,
912 'role': member.role,
913 'reasons': member.reasons,
913 'reasons': member.reasons,
914 'allowed_to_update': member.allowed_to_update,
914 'allowed_to_update': member.allowed_to_update,
915 'review_status': member.review_status,
915 'review_status': member.review_status,
916 'review_status_label': member.review_status_label,
916 'review_status_label': member.review_status_label,
917 'user_group': member.user_group,
917 'user_group': member.user_group,
918 'create': false
918 'create': false
919 });
919 });
920
920
921 $(self.controller.$observerMembers.selector).append(entry)
921 $(self.controller.$observerMembers.selector).append(entry)
922 }
922 }
923 });
923 });
924
924
925 tooltipActivate();
925 tooltipActivate();
926 },
926 },
927
927
928 edit: function (event) {
928 edit: function (event) {
929 this.editButton.hide();
929 this.editButton.hide();
930 this.closeButton.show();
930 this.closeButton.show();
931 this.addButton.show();
931 this.addButton.show();
932 $(this.removeButtons.selector).css('visibility', 'visible');
932 $(this.removeButtons.selector).css('visibility', 'visible');
933 },
933 },
934
934
935 close: function (event) {
935 close: function (event) {
936 this.editButton.show();
936 this.editButton.show();
937 this.closeButton.hide();
937 this.closeButton.hide();
938 this.addButton.hide();
938 this.addButton.hide();
939 $(this.removeButtons.selector).css('visibility', 'hidden');
939 $(this.removeButtons.selector).css('visibility', 'hidden');
940 }
940 }
941
941
942 };
942 };
943
943
944 window.PRDetails = {
944 window.PRDetails = {
945 editButton: null,
945 editButton: null,
946 closeButton: null,
946 closeButton: null,
947 deleteButton: null,
947 deleteButton: null,
948 viewFields: null,
948 viewFields: null,
949 editFields: null,
949 editFields: null,
950
950
951 setSelectors: function () {
951 setSelectors: function () {
952 var self = this;
952 var self = this;
953 self.editButton = $('#open_edit_pullrequest')
953 self.editButton = $('#open_edit_pullrequest')
954 self.closeButton = $('#close_edit_pullrequest')
954 self.closeButton = $('#close_edit_pullrequest')
955 self.deleteButton = $('#delete_pullrequest')
955 self.deleteButton = $('#delete_pullrequest')
956 self.viewFields = $('#pr-desc, #pr-title')
956 self.viewFields = $('#pr-desc, #pr-title')
957 self.editFields = $('#pr-desc-edit, #pr-title-edit, .pr-save')
957 self.editFields = $('#pr-desc-edit, #pr-title-edit, .pr-save')
958 },
958 },
959
959
960 init: function () {
960 init: function () {
961 var self = this;
961 var self = this;
962 self.setSelectors();
962 self.setSelectors();
963 self.editButton.on('click', function (e) {
963 self.editButton.on('click', function (e) {
964 self.edit();
964 self.edit();
965 });
965 });
966 self.closeButton.on('click', function (e) {
966 self.closeButton.on('click', function (e) {
967 self.view();
967 self.view();
968 });
968 });
969 },
969 },
970
970
971 edit: function (event) {
971 edit: function (event) {
972 var cmInstance = $('#pr-description-input').get(0).MarkupForm.cm;
972 var cmInstance = $('#pr-description-input').get(0).MarkupForm.cm;
973 this.viewFields.hide();
973 this.viewFields.hide();
974 this.editButton.hide();
974 this.editButton.hide();
975 this.deleteButton.hide();
975 this.deleteButton.hide();
976 this.closeButton.show();
976 this.closeButton.show();
977 this.editFields.show();
977 this.editFields.show();
978 cmInstance.refresh();
978 cmInstance.refresh();
979 },
979 },
980
980
981 view: function (event) {
981 view: function (event) {
982 this.editButton.show();
982 this.editButton.show();
983 this.deleteButton.show();
983 this.deleteButton.show();
984 this.editFields.hide();
984 this.editFields.hide();
985 this.closeButton.hide();
985 this.closeButton.hide();
986 this.viewFields.show();
986 this.viewFields.show();
987 }
987 }
988 };
988 };
989
989
990 /**
990 /**
991 * OnLine presence using channelstream
991 * OnLine presence using channelstream
992 */
992 */
993 window.ReviewerPresenceController = function (channel) {
993 window.ReviewerPresenceController = function (channel) {
994 var self = this;
994 var self = this;
995 this.channel = channel;
995 this.channel = channel;
996 this.users = {};
996 this.users = {};
997
997
998 this.storeUsers = function (users) {
998 this.storeUsers = function (users) {
999 self.users = {}
999 self.users = {}
1000 $.each(users, function (index, value) {
1000 $.each(users, function (index, value) {
1001 var userId = value.state.id;
1001 var userId = value.state.id;
1002 self.users[userId] = value.state;
1002 self.users[userId] = value.state;
1003 })
1003 })
1004 }
1004 }
1005
1005
1006 this.render = function () {
1006 this.render = function () {
1007 $.each($('.reviewer_entry'), function (index, value) {
1007 $.each($('.reviewer_entry'), function (index, value) {
1008 var userData = $(value).data();
1008 var userData = $(value).data();
1009 if (self.users[userData.reviewerUserId] !== undefined) {
1009 if (self.users[userData.reviewerUserId] !== undefined) {
1010 $(value).find('.presence-state').show();
1010 $(value).find('.presence-state').show();
1011 } else {
1011 } else {
1012 $(value).find('.presence-state').hide();
1012 $(value).find('.presence-state').hide();
1013 }
1013 }
1014 })
1014 })
1015 };
1015 };
1016
1016
1017 this.handlePresence = function (data) {
1017 this.handlePresence = function (data) {
1018 if (data.type == 'presence' && data.channel === self.channel) {
1018 if (data.type == 'presence' && data.channel === self.channel) {
1019 this.storeUsers(data.users);
1019 this.storeUsers(data.users);
1020 this.render();
1020 this.render();
1021 }
1021 }
1022 };
1022 };
1023
1023
1024 this.handleChannelUpdate = function (data) {
1024 this.handleChannelUpdate = function (data) {
1025 if (data.channel === this.channel) {
1025 if (data.channel === this.channel) {
1026 this.storeUsers(data.state.users);
1026 this.storeUsers(data.state.users);
1027 this.render();
1027 this.render();
1028 }
1028 }
1029
1029
1030 };
1030 };
1031
1031
1032 /* subscribe to the current presence */
1032 /* subscribe to the current presence */
1033 $.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
1033 $.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
1034 /* subscribe to updates e.g connect/disconnect */
1034 /* subscribe to updates e.g connect/disconnect */
1035 $.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
1035 $.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
1036
1036
1037 };
1037 };
1038
1038
1039 window.refreshCommentsSuccess = function(targetNode, counterNode, extraCallback) {
1039 window.refreshCommentsSuccess = function(targetNode, counterNode, extraCallback) {
1040 var $targetElem = targetNode;
1040 var $targetElem = targetNode;
1041 var $counterElem = counterNode;
1041 var $counterElem = counterNode;
1042
1042
1043 return function (data) {
1043 return function (data) {
1044 var newCount = $(data).data('counter');
1044 var newCount = $(data).data('counter');
1045 if (newCount !== undefined) {
1045 if (newCount !== undefined) {
1046 var callback = function () {
1046 var callback = function () {
1047 $counterElem.animate({'opacity': 1.00}, 200)
1047 $counterElem.animate({'opacity': 1.00}, 200)
1048 $counterElem.html(newCount);
1048 $counterElem.html(newCount);
1049 };
1049 };
1050 $counterElem.animate({'opacity': 0.15}, 200, callback);
1050 $counterElem.animate({'opacity': 0.15}, 200, callback);
1051 }
1051 }
1052
1052
1053 $targetElem.css('opacity', 1);
1053 $targetElem.css('opacity', 1);
1054 $targetElem.html(data);
1054 $targetElem.html(data);
1055 tooltipActivate();
1055 tooltipActivate();
1056
1056
1057 if (extraCallback !== undefined) {
1057 if (extraCallback !== undefined) {
1058 extraCallback(data)
1058 extraCallback(data)
1059 }
1059 }
1060 }
1060 }
1061 }
1061 }
1062
1062
1063 window.refreshComments = function (version) {
1063 window.refreshComments = function (version) {
1064 version = version || templateContext.pull_request_data.pull_request_version || '';
1064 version = version || templateContext.pull_request_data.pull_request_version || '';
1065
1065
1066 // Pull request case
1066 // Pull request case
1067 if (templateContext.pull_request_data.pull_request_id !== null) {
1067 if (templateContext.pull_request_data.pull_request_id !== null) {
1068 var params = {
1068 var params = {
1069 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1069 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1070 'repo_name': templateContext.repo_name,
1070 'repo_name': templateContext.repo_name,
1071 'version': version,
1071 'version': version,
1072 };
1072 };
1073 var loadUrl = pyroutes.url('pullrequest_comments', params);
1073 var loadUrl = pyroutes.url('pullrequest_comments', params);
1074 } // commit case
1074 } // commit case
1075 else {
1075 else {
1076 return
1076 return
1077 }
1077 }
1078
1078
1079 var currentIDs = []
1079 var currentIDs = []
1080 $.each($('.comment'), function (idx, element) {
1080 $.each($('.comment'), function (idx, element) {
1081 currentIDs.push($(element).data('commentId'));
1081 currentIDs.push($(element).data('commentId'));
1082 });
1082 });
1083 var data = {"comments": currentIDs};
1083 var data = {"comments": currentIDs};
1084
1084
1085 var $targetElem = $('.comments-content-table');
1085 var $targetElem = $('.comments-content-table');
1086 $targetElem.css('opacity', 0.3);
1086 $targetElem.css('opacity', 0.3);
1087 var $counterElem = $('#comments-count');
1087 var $counterElem = $('#comments-count');
1088 var success = refreshCommentsSuccess($targetElem, $counterElem);
1088 var success = refreshCommentsSuccess($targetElem, $counterElem);
1089 ajaxPOST(loadUrl, data, success, null, {})
1089 ajaxPOST(loadUrl, data, success, null, {})
1090
1090
1091 }
1091 }
1092
1092
1093 window.refreshTODOs = function (version) {
1093 window.refreshTODOs = function (version) {
1094 version = version || templateContext.pull_request_data.pull_request_version || '';
1094 version = version || templateContext.pull_request_data.pull_request_version || '';
1095 // Pull request case
1095 // Pull request case
1096 if (templateContext.pull_request_data.pull_request_id !== null) {
1096 if (templateContext.pull_request_data.pull_request_id !== null) {
1097 var params = {
1097 var params = {
1098 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1098 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1099 'repo_name': templateContext.repo_name,
1099 'repo_name': templateContext.repo_name,
1100 'version': version,
1100 'version': version,
1101 };
1101 };
1102 var loadUrl = pyroutes.url('pullrequest_todos', params);
1102 var loadUrl = pyroutes.url('pullrequest_todos', params);
1103 } // commit case
1103 } // commit case
1104 else {
1104 else {
1105 return
1105 return
1106 }
1106 }
1107
1107
1108 var currentIDs = []
1108 var currentIDs = []
1109 $.each($('.comment'), function (idx, element) {
1109 $.each($('.comment'), function (idx, element) {
1110 currentIDs.push($(element).data('commentId'));
1110 currentIDs.push($(element).data('commentId'));
1111 });
1111 });
1112
1112
1113 var data = {"comments": currentIDs};
1113 var data = {"comments": currentIDs};
1114 var $targetElem = $('.todos-content-table');
1114 var $targetElem = $('.todos-content-table');
1115 $targetElem.css('opacity', 0.3);
1115 $targetElem.css('opacity', 0.3);
1116 var $counterElem = $('#todos-count');
1116 var $counterElem = $('#todos-count');
1117 var success = refreshCommentsSuccess($targetElem, $counterElem);
1117 var success = refreshCommentsSuccess($targetElem, $counterElem);
1118
1118
1119 ajaxPOST(loadUrl, data, success, null, {})
1119 ajaxPOST(loadUrl, data, success, null, {})
1120
1120
1121 }
1121 }
1122
1122
1123 window.refreshDraftComments = function () {
1123 window.refreshDraftComments = function () {
1124
1124
1125 // Pull request case
1125 // Pull request case
1126 if (templateContext.pull_request_data.pull_request_id !== null) {
1126 if (templateContext.pull_request_data.pull_request_id !== null) {
1127 var params = {
1127 var params = {
1128 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1128 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1129 'repo_name': templateContext.repo_name,
1129 'repo_name': templateContext.repo_name,
1130 };
1130 };
1131 var loadUrl = pyroutes.url('pullrequest_drafts', params);
1131 var loadUrl = pyroutes.url('pullrequest_drafts', params);
1132 } // commit case
1132 } // commit case
1133 else {
1133 else {
1134 return
1134 return
1135 }
1135 }
1136
1136
1137 var data = {};
1137 var data = {};
1138
1138
1139 var $targetElem = $('.drafts-content-table');
1139 var $targetElem = $('.drafts-content-table');
1140 $targetElem.css('opacity', 0.3);
1140 $targetElem.css('opacity', 0.3);
1141 var $counterElem = $('#drafts-count');
1141 var $counterElem = $('#drafts-count');
1142 var extraCallback = function(data) {
1142 var extraCallback = function(data) {
1143 if ($(data).data('counter') == 0){
1143 if ($(data).data('counter') == 0){
1144 $('#draftsTable').hide();
1144 $('#draftsTable').hide();
1145 } else {
1145 } else {
1146 $('#draftsTable').show();
1146 $('#draftsTable').show();
1147 }
1147 }
1148 // uncheck on load the select all checkbox
1148 // uncheck on load the select all checkbox
1149 $('[name=select_all_drafts]').prop('checked', 0);
1149 $('[name=select_all_drafts]').prop('checked', 0);
1150 }
1150 }
1151 var success = refreshCommentsSuccess($targetElem, $counterElem, extraCallback);
1151 var success = refreshCommentsSuccess($targetElem, $counterElem, extraCallback);
1152
1152
1153 ajaxPOST(loadUrl, data, success, null, {})
1153 ajaxPOST(loadUrl, data, success, null, {})
1154 };
1154 };
1155
1155
1156 window.refreshAllComments = function (version) {
1156 window.refreshAllComments = function (version) {
1157 version = version || templateContext.pull_request_data.pull_request_version || '';
1157 version = version || templateContext.pull_request_data.pull_request_version || '';
1158
1158
1159 refreshComments(version);
1159 refreshComments(version);
1160 refreshTODOs(version);
1160 refreshTODOs(version);
1161 };
1161 };
1162
1162
1163 window.sidebarComment = function (commentId) {
1163 window.sidebarComment = function (commentId) {
1164 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1164 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1165 if (!jsonData) {
1165 if (!jsonData) {
1166 return 'Failed to load comment {0}'.format(commentId)
1166 return 'Failed to load comment {0}'.format(commentId)
1167 }
1167 }
1168 var funcData = JSON.parse(atob(jsonData));
1168 var funcData = JSON.parse(atob(jsonData));
1169 return renderTemplate('sideBarCommentHovercard', funcData)
1169 return renderTemplate('sideBarCommentHovercard', funcData)
1170 };
1170 };
General Comments 0
You need to be logged in to leave comments. Login now