##// END OF EJS Templates
sidebar: fixed refresh of TODOs url.
milka -
r4539:12a7b92d default
parent child Browse files
Show More
@@ -1,1191 +1,1191 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(
185 self.addRule(
186 _gettext('All reviewers must vote.'))
186 _gettext('All reviewers must vote.'))
187 );
187 );
188 return self.forbidUsers
188 return self.forbidUsers
189 }
189 }
190
190
191 if (data.rules.voting !== undefined) {
191 if (data.rules.voting !== undefined) {
192 if (data.rules.voting < 0) {
192 if (data.rules.voting < 0) {
193 self.$rulesList.append(
193 self.$rulesList.append(
194 self.addRule(
194 self.addRule(
195 _gettext('All individual reviewers must vote.'))
195 _gettext('All individual reviewers must vote.'))
196 )
196 )
197 } else if (data.rules.voting === 1) {
197 } else if (data.rules.voting === 1) {
198 self.$rulesList.append(
198 self.$rulesList.append(
199 self.addRule(
199 self.addRule(
200 _gettext('At least {0} reviewer must vote.').format(data.rules.voting))
200 _gettext('At least {0} reviewer must vote.').format(data.rules.voting))
201 )
201 )
202
202
203 } else {
203 } else {
204 self.$rulesList.append(
204 self.$rulesList.append(
205 self.addRule(
205 self.addRule(
206 _gettext('At least {0} reviewers must vote.').format(data.rules.voting))
206 _gettext('At least {0} reviewers must vote.').format(data.rules.voting))
207 )
207 )
208 }
208 }
209 }
209 }
210
210
211 if (data.rules.voting_groups !== undefined) {
211 if (data.rules.voting_groups !== undefined) {
212 $.each(data.rules.voting_groups, function (index, rule_data) {
212 $.each(data.rules.voting_groups, function (index, rule_data) {
213 self.$rulesList.append(
213 self.$rulesList.append(
214 self.addRule(rule_data.text)
214 self.addRule(rule_data.text)
215 )
215 )
216 });
216 });
217 }
217 }
218
218
219 if (data.rules.use_code_authors_for_review) {
219 if (data.rules.use_code_authors_for_review) {
220 self.$rulesList.append(
220 self.$rulesList.append(
221 self.addRule(
221 self.addRule(
222 _gettext('Reviewers picked from source code changes.'))
222 _gettext('Reviewers picked from source code changes.'))
223 )
223 )
224 }
224 }
225
225
226 if (data.rules.forbid_adding_reviewers) {
226 if (data.rules.forbid_adding_reviewers) {
227 $('#add_reviewer_input').remove();
227 $('#add_reviewer_input').remove();
228 self.$rulesList.append(
228 self.$rulesList.append(
229 self.addRule(
229 self.addRule(
230 _gettext('Adding new reviewers is forbidden.'))
230 _gettext('Adding new reviewers is forbidden.'))
231 )
231 )
232 }
232 }
233
233
234 if (data.rules.forbid_author_to_review) {
234 if (data.rules.forbid_author_to_review) {
235 self.forbidUsers.push(data.rules_data.pr_author);
235 self.forbidUsers.push(data.rules_data.pr_author);
236 self.$rulesList.append(
236 self.$rulesList.append(
237 self.addRule(
237 self.addRule(
238 _gettext('Author is not allowed to be a reviewer.'))
238 _gettext('Author is not allowed to be a reviewer.'))
239 )
239 )
240 }
240 }
241
241
242 if (data.rules.forbid_commit_author_to_review) {
242 if (data.rules.forbid_commit_author_to_review) {
243
243
244 if (data.rules_data.forbidden_users) {
244 if (data.rules_data.forbidden_users) {
245 $.each(data.rules_data.forbidden_users, function (index, member_data) {
245 $.each(data.rules_data.forbidden_users, function (index, member_data) {
246 self.forbidUsers.push(member_data)
246 self.forbidUsers.push(member_data)
247 });
247 });
248 }
248 }
249
249
250 self.$rulesList.append(
250 self.$rulesList.append(
251 self.addRule(
251 self.addRule(
252 _gettext('Commit Authors are not allowed to be a reviewer.'))
252 _gettext('Commit Authors are not allowed to be a reviewer.'))
253 )
253 )
254 }
254 }
255
255
256 // we don't have any rules set, so we inform users about it
256 // we don't have any rules set, so we inform users about it
257 if (self.enabledRules.length === 0) {
257 if (self.enabledRules.length === 0) {
258 self.addRule(
258 self.addRule(
259 _gettext('No review rules set.'))
259 _gettext('No review rules set.'))
260 }
260 }
261
261
262 return self.forbidUsers
262 return self.forbidUsers
263 };
263 };
264
264
265 this.emptyTables = function () {
265 this.emptyTables = function () {
266 self.emptyReviewersTable();
266 self.emptyReviewersTable();
267 self.emptyObserversTable();
267 self.emptyObserversTable();
268
268
269 // Also reset counters.
269 // Also reset counters.
270 self.resetCounter();
270 self.resetCounter();
271 }
271 }
272
272
273 this.emptyReviewersTable = function (withText) {
273 this.emptyReviewersTable = function (withText) {
274 self.$reviewMembers.empty();
274 self.$reviewMembers.empty();
275 if (withText !== undefined) {
275 if (withText !== undefined) {
276 self.$reviewMembers.html(withText)
276 self.$reviewMembers.html(withText)
277 }
277 }
278 };
278 };
279
279
280 this.emptyObserversTable = function (withText) {
280 this.emptyObserversTable = function (withText) {
281 self.$observerMembers.empty();
281 self.$observerMembers.empty();
282 if (withText !== undefined) {
282 if (withText !== undefined) {
283 self.$observerMembers.html(withText)
283 self.$observerMembers.html(withText)
284 }
284 }
285 }
285 }
286
286
287 this.loadDefaultReviewers = function (sourceRepo, sourceRef, targetRepo, targetRef) {
287 this.loadDefaultReviewers = function (sourceRepo, sourceRef, targetRepo, targetRef) {
288
288
289 if (self.currentRequest) {
289 if (self.currentRequest) {
290 // make sure we cleanup old running requests before triggering this again
290 // make sure we cleanup old running requests before triggering this again
291 self.currentRequest.abort();
291 self.currentRequest.abort();
292 }
292 }
293
293
294 self.$loadingIndicator.show();
294 self.$loadingIndicator.show();
295
295
296 // reset reviewer/observe members
296 // reset reviewer/observe members
297 self.emptyTables();
297 self.emptyTables();
298
298
299 prButtonLock(true, null, 'reviewers');
299 prButtonLock(true, null, 'reviewers');
300 $('#user').hide(); // hide user autocomplete before load
300 $('#user').hide(); // hide user autocomplete before load
301 $('#observer').hide(); //hide observer autocomplete before load
301 $('#observer').hide(); //hide observer autocomplete before load
302
302
303 // lock PR button, so we cannot send PR before it's calculated
303 // lock PR button, so we cannot send PR before it's calculated
304 prButtonLock(true, _gettext('Loading diff ...'), 'compare');
304 prButtonLock(true, _gettext('Loading diff ...'), 'compare');
305
305
306 if (sourceRef.length !== 3 || targetRef.length !== 3) {
306 if (sourceRef.length !== 3 || targetRef.length !== 3) {
307 // don't load defaults in case we're missing some refs...
307 // don't load defaults in case we're missing some refs...
308 self.$loadingIndicator.hide();
308 self.$loadingIndicator.hide();
309 return
309 return
310 }
310 }
311
311
312 var url = pyroutes.url('repo_default_reviewers_data',
312 var url = pyroutes.url('repo_default_reviewers_data',
313 {
313 {
314 'repo_name': templateContext.repo_name,
314 'repo_name': templateContext.repo_name,
315 'source_repo': sourceRepo,
315 'source_repo': sourceRepo,
316 'source_ref_type': sourceRef[0],
316 'source_ref_type': sourceRef[0],
317 'source_ref_name': sourceRef[1],
317 'source_ref_name': sourceRef[1],
318 'source_ref': sourceRef[2],
318 'source_ref': sourceRef[2],
319 'target_repo': targetRepo,
319 'target_repo': targetRepo,
320 'target_ref': targetRef[2],
320 'target_ref': targetRef[2],
321 'target_ref_type': sourceRef[0],
321 'target_ref_type': sourceRef[0],
322 'target_ref_name': sourceRef[1]
322 'target_ref_name': sourceRef[1]
323 });
323 });
324
324
325 self.currentRequest = $.ajax({
325 self.currentRequest = $.ajax({
326 url: url,
326 url: url,
327 headers: {'X-PARTIAL-XHR': true},
327 headers: {'X-PARTIAL-XHR': true},
328 type: 'GET',
328 type: 'GET',
329 success: function (data) {
329 success: function (data) {
330
330
331 self.currentRequest = null;
331 self.currentRequest = null;
332
332
333 // review rules
333 // review rules
334 self.loadReviewRules(data);
334 self.loadReviewRules(data);
335 var diffHandled = self.handleDiffData(data["diff_info"]);
335 var diffHandled = self.handleDiffData(data["diff_info"]);
336 if (diffHandled === false) {
336 if (diffHandled === false) {
337 return
337 return
338 }
338 }
339
339
340 for (var i = 0; i < data.reviewers.length; i++) {
340 for (var i = 0; i < data.reviewers.length; i++) {
341 var reviewer = data.reviewers[i];
341 var reviewer = data.reviewers[i];
342 // load reviewer rules from the repo data
342 // load reviewer rules from the repo data
343 self.addMember(reviewer, reviewer.reasons, reviewer.mandatory, reviewer.role);
343 self.addMember(reviewer, reviewer.reasons, reviewer.mandatory, reviewer.role);
344 }
344 }
345
345
346
346
347 self.$loadingIndicator.hide();
347 self.$loadingIndicator.hide();
348 prButtonLock(false, null, 'reviewers');
348 prButtonLock(false, null, 'reviewers');
349
349
350 $('#user').show(); // show user autocomplete before load
350 $('#user').show(); // show user autocomplete before load
351 $('#observer').show(); // show observer autocomplete before load
351 $('#observer').show(); // show observer autocomplete before load
352
352
353 var commitElements = data["diff_info"]['commits'];
353 var commitElements = data["diff_info"]['commits'];
354
354
355 if (commitElements.length === 0) {
355 if (commitElements.length === 0) {
356 var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
356 var noCommitsMsg = '<span class="alert-text-warning">{0}</span>'.format(
357 _gettext('There are no commits to merge.'));
357 _gettext('There are no commits to merge.'));
358 prButtonLock(true, noCommitsMsg, 'all');
358 prButtonLock(true, noCommitsMsg, 'all');
359
359
360 } else {
360 } else {
361 // un-lock PR button, so we cannot send PR before it's calculated
361 // un-lock PR button, so we cannot send PR before it's calculated
362 prButtonLock(false, null, 'compare');
362 prButtonLock(false, null, 'compare');
363 }
363 }
364
364
365 },
365 },
366 error: function (jqXHR, textStatus, errorThrown) {
366 error: function (jqXHR, textStatus, errorThrown) {
367 var prefix = "Loading diff and reviewers/observers failed\n"
367 var prefix = "Loading diff and reviewers/observers failed\n"
368 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
368 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
369 ajaxErrorSwal(message);
369 ajaxErrorSwal(message);
370 }
370 }
371 });
371 });
372
372
373 };
373 };
374
374
375 // check those, refactor
375 // check those, refactor
376 this.removeMember = function (reviewer_id, mark_delete) {
376 this.removeMember = function (reviewer_id, mark_delete) {
377 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
377 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
378
378
379 if (typeof (mark_delete) === undefined) {
379 if (typeof (mark_delete) === undefined) {
380 mark_delete = false;
380 mark_delete = false;
381 }
381 }
382
382
383 if (mark_delete === true) {
383 if (mark_delete === true) {
384 if (reviewer) {
384 if (reviewer) {
385 // now delete the input
385 // now delete the input
386 $('#reviewer_{0} input'.format(reviewer_id)).remove();
386 $('#reviewer_{0} input'.format(reviewer_id)).remove();
387 $('#reviewer_{0}_rules input'.format(reviewer_id)).remove();
387 $('#reviewer_{0}_rules input'.format(reviewer_id)).remove();
388 // mark as to-delete
388 // mark as to-delete
389 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
389 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
390 obj.addClass('to-delete');
390 obj.addClass('to-delete');
391 obj.css({"text-decoration": "line-through", "opacity": 0.5});
391 obj.css({"text-decoration": "line-through", "opacity": 0.5});
392 }
392 }
393 } else {
393 } else {
394 $('#reviewer_{0}'.format(reviewer_id)).remove();
394 $('#reviewer_{0}'.format(reviewer_id)).remove();
395 }
395 }
396 };
396 };
397
397
398 this.addMember = function (reviewer_obj, reasons, mandatory, role) {
398 this.addMember = function (reviewer_obj, reasons, mandatory, role) {
399
399
400 var id = reviewer_obj.user_id;
400 var id = reviewer_obj.user_id;
401 var username = reviewer_obj.username;
401 var username = reviewer_obj.username;
402
402
403 reasons = reasons || [];
403 reasons = reasons || [];
404 mandatory = mandatory || false;
404 mandatory = mandatory || false;
405 role = role || self.ROLE_REVIEWER
405 role = role || self.ROLE_REVIEWER
406
406
407 // register current set IDS to check if we don't have this ID already in
407 // register current set IDS to check if we don't have this ID already in
408 // and prevent duplicates
408 // and prevent duplicates
409 var currentIds = [];
409 var currentIds = [];
410
410
411 $.each($('.reviewer_entry'), function (index, value) {
411 $.each($('.reviewer_entry'), function (index, value) {
412 currentIds.push($(value).data('reviewerUserId'))
412 currentIds.push($(value).data('reviewerUserId'))
413 })
413 })
414
414
415 var userAllowedReview = function (userId) {
415 var userAllowedReview = function (userId) {
416 var allowed = true;
416 var allowed = true;
417 $.each(self.forbidUsers, function (index, member_data) {
417 $.each(self.forbidUsers, function (index, member_data) {
418 if (parseInt(userId) === member_data['user_id']) {
418 if (parseInt(userId) === member_data['user_id']) {
419 allowed = false;
419 allowed = false;
420 return false // breaks the loop
420 return false // breaks the loop
421 }
421 }
422 });
422 });
423 return allowed
423 return allowed
424 };
424 };
425
425
426 var userAllowed = userAllowedReview(id);
426 var userAllowed = userAllowedReview(id);
427
427
428 if (!userAllowed) {
428 if (!userAllowed) {
429 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
429 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
430 } else {
430 } else {
431 // only add if it's not there
431 // only add if it's not there
432 var alreadyReviewer = currentIds.indexOf(id) != -1;
432 var alreadyReviewer = currentIds.indexOf(id) != -1;
433
433
434 if (alreadyReviewer) {
434 if (alreadyReviewer) {
435 alert(_gettext('User `{0}` already in reviewers/observers').format(username));
435 alert(_gettext('User `{0}` already in reviewers/observers').format(username));
436 } else {
436 } else {
437
437
438 var reviewerEntry = renderTemplate('reviewMemberEntry', {
438 var reviewerEntry = renderTemplate('reviewMemberEntry', {
439 'member': reviewer_obj,
439 'member': reviewer_obj,
440 'mandatory': mandatory,
440 'mandatory': mandatory,
441 'role': role,
441 'role': role,
442 'reasons': reasons,
442 'reasons': reasons,
443 'allowed_to_update': true,
443 'allowed_to_update': true,
444 'review_status': 'not_reviewed',
444 'review_status': 'not_reviewed',
445 'review_status_label': _gettext('Not Reviewed'),
445 'review_status_label': _gettext('Not Reviewed'),
446 'user_group': reviewer_obj.user_group,
446 'user_group': reviewer_obj.user_group,
447 'create': true,
447 'create': true,
448 'rule_show': true,
448 'rule_show': true,
449 })
449 })
450
450
451 if (role === self.ROLE_REVIEWER) {
451 if (role === self.ROLE_REVIEWER) {
452 $(self.$reviewMembers.selector).append(reviewerEntry);
452 $(self.$reviewMembers.selector).append(reviewerEntry);
453 self.increaseCounter(self.ROLE_REVIEWER);
453 self.increaseCounter(self.ROLE_REVIEWER);
454 $('#reviewer-empty-msg').remove()
454 $('#reviewer-empty-msg').remove()
455 }
455 }
456 else if (role === self.ROLE_OBSERVER) {
456 else if (role === self.ROLE_OBSERVER) {
457 $(self.$observerMembers.selector).append(reviewerEntry);
457 $(self.$observerMembers.selector).append(reviewerEntry);
458 self.increaseCounter(self.ROLE_OBSERVER);
458 self.increaseCounter(self.ROLE_OBSERVER);
459 $('#observer-empty-msg').remove();
459 $('#observer-empty-msg').remove();
460 }
460 }
461
461
462 tooltipActivate();
462 tooltipActivate();
463 }
463 }
464 }
464 }
465
465
466 };
466 };
467
467
468 this.updateReviewers = function (repo_name, pull_request_id, role) {
468 this.updateReviewers = function (repo_name, pull_request_id, role) {
469 if (role === 'reviewer') {
469 if (role === 'reviewer') {
470 var postData = $('#reviewers input').serialize();
470 var postData = $('#reviewers input').serialize();
471 _updatePullRequest(repo_name, pull_request_id, postData);
471 _updatePullRequest(repo_name, pull_request_id, postData);
472 } else if (role === 'observer') {
472 } else if (role === 'observer') {
473 var postData = $('#observers input').serialize();
473 var postData = $('#observers input').serialize();
474 _updatePullRequest(repo_name, pull_request_id, postData);
474 _updatePullRequest(repo_name, pull_request_id, postData);
475 }
475 }
476 };
476 };
477
477
478 this.handleDiffData = function (data) {
478 this.handleDiffData = function (data) {
479 return self.diffDataHandler(data)
479 return self.diffDataHandler(data)
480 }
480 }
481 };
481 };
482
482
483
483
484 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
484 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
485 var url = pyroutes.url(
485 var url = pyroutes.url(
486 'pullrequest_update',
486 'pullrequest_update',
487 {"repo_name": repo_name, "pull_request_id": pull_request_id});
487 {"repo_name": repo_name, "pull_request_id": pull_request_id});
488 if (typeof postData === 'string' ) {
488 if (typeof postData === 'string' ) {
489 postData += '&csrf_token=' + CSRF_TOKEN;
489 postData += '&csrf_token=' + CSRF_TOKEN;
490 } else {
490 } else {
491 postData.csrf_token = CSRF_TOKEN;
491 postData.csrf_token = CSRF_TOKEN;
492 }
492 }
493
493
494 var success = function(o) {
494 var success = function(o) {
495 var redirectUrl = o['redirect_url'];
495 var redirectUrl = o['redirect_url'];
496 if (redirectUrl !== undefined && redirectUrl !== null && redirectUrl !== '') {
496 if (redirectUrl !== undefined && redirectUrl !== null && redirectUrl !== '') {
497 window.location = redirectUrl;
497 window.location = redirectUrl;
498 } else {
498 } else {
499 window.location.reload();
499 window.location.reload();
500 }
500 }
501 };
501 };
502
502
503 ajaxPOST(url, postData, success);
503 ajaxPOST(url, postData, success);
504 };
504 };
505
505
506 /**
506 /**
507 * PULL REQUEST update commits
507 * PULL REQUEST update commits
508 */
508 */
509 var updateCommits = function(repo_name, pull_request_id, force) {
509 var updateCommits = function(repo_name, pull_request_id, force) {
510 var postData = {
510 var postData = {
511 'update_commits': true
511 'update_commits': true
512 };
512 };
513 if (force !== undefined && force === true) {
513 if (force !== undefined && force === true) {
514 postData['force_refresh'] = true
514 postData['force_refresh'] = true
515 }
515 }
516 _updatePullRequest(repo_name, pull_request_id, postData);
516 _updatePullRequest(repo_name, pull_request_id, postData);
517 };
517 };
518
518
519
519
520 /**
520 /**
521 * PULL REQUEST edit info
521 * PULL REQUEST edit info
522 */
522 */
523 var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) {
523 var editPullRequest = function(repo_name, pull_request_id, title, description, renderer) {
524 var url = pyroutes.url(
524 var url = pyroutes.url(
525 'pullrequest_update',
525 'pullrequest_update',
526 {"repo_name": repo_name, "pull_request_id": pull_request_id});
526 {"repo_name": repo_name, "pull_request_id": pull_request_id});
527
527
528 var postData = {
528 var postData = {
529 'title': title,
529 'title': title,
530 'description': description,
530 'description': description,
531 'description_renderer': renderer,
531 'description_renderer': renderer,
532 'edit_pull_request': true,
532 'edit_pull_request': true,
533 'csrf_token': CSRF_TOKEN
533 'csrf_token': CSRF_TOKEN
534 };
534 };
535 var success = function(o) {
535 var success = function(o) {
536 window.location.reload();
536 window.location.reload();
537 };
537 };
538 ajaxPOST(url, postData, success);
538 ajaxPOST(url, postData, success);
539 };
539 };
540
540
541
541
542 /**
542 /**
543 * autocomplete handler for reviewers/observers
543 * autocomplete handler for reviewers/observers
544 */
544 */
545 var autoCompleteHandler = function (inputId, controller, role) {
545 var autoCompleteHandler = function (inputId, controller, role) {
546
546
547 return function (element, data) {
547 return function (element, data) {
548 var mandatory = false;
548 var mandatory = false;
549 var reasons = [_gettext('added manually by "{0}"').format(
549 var reasons = [_gettext('added manually by "{0}"').format(
550 templateContext.rhodecode_user.username)];
550 templateContext.rhodecode_user.username)];
551
551
552 // add whole user groups
552 // add whole user groups
553 if (data.value_type == 'user_group') {
553 if (data.value_type == 'user_group') {
554 reasons.push(_gettext('member of "{0}"').format(data.value_display));
554 reasons.push(_gettext('member of "{0}"').format(data.value_display));
555
555
556 $.each(data.members, function (index, member_data) {
556 $.each(data.members, function (index, member_data) {
557 var reviewer = member_data;
557 var reviewer = member_data;
558 reviewer['user_id'] = member_data['id'];
558 reviewer['user_id'] = member_data['id'];
559 reviewer['gravatar_link'] = member_data['icon_link'];
559 reviewer['gravatar_link'] = member_data['icon_link'];
560 reviewer['user_link'] = member_data['profile_link'];
560 reviewer['user_link'] = member_data['profile_link'];
561 reviewer['rules'] = [];
561 reviewer['rules'] = [];
562 controller.addMember(reviewer, reasons, mandatory, role);
562 controller.addMember(reviewer, reasons, mandatory, role);
563 })
563 })
564 }
564 }
565 // add single user
565 // add single user
566 else {
566 else {
567 var reviewer = data;
567 var reviewer = data;
568 reviewer['user_id'] = data['id'];
568 reviewer['user_id'] = data['id'];
569 reviewer['gravatar_link'] = data['icon_link'];
569 reviewer['gravatar_link'] = data['icon_link'];
570 reviewer['user_link'] = data['profile_link'];
570 reviewer['user_link'] = data['profile_link'];
571 reviewer['rules'] = [];
571 reviewer['rules'] = [];
572 controller.addMember(reviewer, reasons, mandatory, role);
572 controller.addMember(reviewer, reasons, mandatory, role);
573 }
573 }
574
574
575 $(inputId).val('');
575 $(inputId).val('');
576 }
576 }
577 }
577 }
578
578
579 /**
579 /**
580 * Reviewer autocomplete
580 * Reviewer autocomplete
581 */
581 */
582 var ReviewerAutoComplete = function (inputId, controller) {
582 var ReviewerAutoComplete = function (inputId, controller) {
583 var self = this;
583 var self = this;
584 self.controller = controller;
584 self.controller = controller;
585 self.inputId = inputId;
585 self.inputId = inputId;
586 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_REVIEWER);
586 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_REVIEWER);
587
587
588 $(inputId).autocomplete({
588 $(inputId).autocomplete({
589 serviceUrl: pyroutes.url('user_autocomplete_data'),
589 serviceUrl: pyroutes.url('user_autocomplete_data'),
590 minChars: 2,
590 minChars: 2,
591 maxHeight: 400,
591 maxHeight: 400,
592 deferRequestBy: 300, //miliseconds
592 deferRequestBy: 300, //miliseconds
593 showNoSuggestionNotice: true,
593 showNoSuggestionNotice: true,
594 tabDisabled: true,
594 tabDisabled: true,
595 autoSelectFirst: true,
595 autoSelectFirst: true,
596 params: {
596 params: {
597 user_id: templateContext.rhodecode_user.user_id,
597 user_id: templateContext.rhodecode_user.user_id,
598 user_groups: true,
598 user_groups: true,
599 user_groups_expand: true,
599 user_groups_expand: true,
600 skip_default_user: true
600 skip_default_user: true
601 },
601 },
602 formatResult: autocompleteFormatResult,
602 formatResult: autocompleteFormatResult,
603 lookupFilter: autocompleteFilterResult,
603 lookupFilter: autocompleteFilterResult,
604 onSelect: handler
604 onSelect: handler
605 });
605 });
606 };
606 };
607
607
608 /**
608 /**
609 * Observers autocomplete
609 * Observers autocomplete
610 */
610 */
611 var ObserverAutoComplete = function(inputId, controller) {
611 var ObserverAutoComplete = function(inputId, controller) {
612 var self = this;
612 var self = this;
613 self.controller = controller;
613 self.controller = controller;
614 self.inputId = inputId;
614 self.inputId = inputId;
615 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_OBSERVER);
615 var handler = autoCompleteHandler(inputId, controller, controller.ROLE_OBSERVER);
616
616
617 $(inputId).autocomplete({
617 $(inputId).autocomplete({
618 serviceUrl: pyroutes.url('user_autocomplete_data'),
618 serviceUrl: pyroutes.url('user_autocomplete_data'),
619 minChars: 2,
619 minChars: 2,
620 maxHeight: 400,
620 maxHeight: 400,
621 deferRequestBy: 300, //miliseconds
621 deferRequestBy: 300, //miliseconds
622 showNoSuggestionNotice: true,
622 showNoSuggestionNotice: true,
623 tabDisabled: true,
623 tabDisabled: true,
624 autoSelectFirst: true,
624 autoSelectFirst: true,
625 params: {
625 params: {
626 user_id: templateContext.rhodecode_user.user_id,
626 user_id: templateContext.rhodecode_user.user_id,
627 user_groups: true,
627 user_groups: true,
628 user_groups_expand: true,
628 user_groups_expand: true,
629 skip_default_user: true
629 skip_default_user: true
630 },
630 },
631 formatResult: autocompleteFormatResult,
631 formatResult: autocompleteFormatResult,
632 lookupFilter: autocompleteFilterResult,
632 lookupFilter: autocompleteFilterResult,
633 onSelect: handler
633 onSelect: handler
634 });
634 });
635 }
635 }
636
636
637
637
638 window.VersionController = function () {
638 window.VersionController = function () {
639 var self = this;
639 var self = this;
640 this.$verSource = $('input[name=ver_source]');
640 this.$verSource = $('input[name=ver_source]');
641 this.$verTarget = $('input[name=ver_target]');
641 this.$verTarget = $('input[name=ver_target]');
642 this.$showVersionDiff = $('#show-version-diff');
642 this.$showVersionDiff = $('#show-version-diff');
643
643
644 this.adjustRadioSelectors = function (curNode) {
644 this.adjustRadioSelectors = function (curNode) {
645 var getVal = function (item) {
645 var getVal = function (item) {
646 if (item === 'latest') {
646 if (item === 'latest') {
647 return Number.MAX_SAFE_INTEGER
647 return Number.MAX_SAFE_INTEGER
648 }
648 }
649 else {
649 else {
650 return parseInt(item)
650 return parseInt(item)
651 }
651 }
652 };
652 };
653
653
654 var curVal = getVal($(curNode).val());
654 var curVal = getVal($(curNode).val());
655 var cleared = false;
655 var cleared = false;
656
656
657 $.each(self.$verSource, function (index, value) {
657 $.each(self.$verSource, function (index, value) {
658 var elVal = getVal($(value).val());
658 var elVal = getVal($(value).val());
659
659
660 if (elVal > curVal) {
660 if (elVal > curVal) {
661 if ($(value).is(':checked')) {
661 if ($(value).is(':checked')) {
662 cleared = true;
662 cleared = true;
663 }
663 }
664 $(value).attr('disabled', 'disabled');
664 $(value).attr('disabled', 'disabled');
665 $(value).removeAttr('checked');
665 $(value).removeAttr('checked');
666 $(value).css({'opacity': 0.1});
666 $(value).css({'opacity': 0.1});
667 }
667 }
668 else {
668 else {
669 $(value).css({'opacity': 1});
669 $(value).css({'opacity': 1});
670 $(value).removeAttr('disabled');
670 $(value).removeAttr('disabled');
671 }
671 }
672 });
672 });
673
673
674 if (cleared) {
674 if (cleared) {
675 // if we unchecked an active, set the next one to same loc.
675 // if we unchecked an active, set the next one to same loc.
676 $(this.$verSource).filter('[value={0}]'.format(
676 $(this.$verSource).filter('[value={0}]'.format(
677 curVal)).attr('checked', 'checked');
677 curVal)).attr('checked', 'checked');
678 }
678 }
679
679
680 self.setLockAction(false,
680 self.setLockAction(false,
681 $(curNode).data('verPos'),
681 $(curNode).data('verPos'),
682 $(this.$verSource).filter(':checked').data('verPos')
682 $(this.$verSource).filter(':checked').data('verPos')
683 );
683 );
684 };
684 };
685
685
686
686
687 this.attachVersionListener = function () {
687 this.attachVersionListener = function () {
688 self.$verTarget.change(function (e) {
688 self.$verTarget.change(function (e) {
689 self.adjustRadioSelectors(this)
689 self.adjustRadioSelectors(this)
690 });
690 });
691 self.$verSource.change(function (e) {
691 self.$verSource.change(function (e) {
692 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
692 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
693 });
693 });
694 };
694 };
695
695
696 this.init = function () {
696 this.init = function () {
697
697
698 var curNode = self.$verTarget.filter(':checked');
698 var curNode = self.$verTarget.filter(':checked');
699 self.adjustRadioSelectors(curNode);
699 self.adjustRadioSelectors(curNode);
700 self.setLockAction(true);
700 self.setLockAction(true);
701 self.attachVersionListener();
701 self.attachVersionListener();
702
702
703 };
703 };
704
704
705 this.setLockAction = function (state, selectedVersion, otherVersion) {
705 this.setLockAction = function (state, selectedVersion, otherVersion) {
706 var $showVersionDiff = this.$showVersionDiff;
706 var $showVersionDiff = this.$showVersionDiff;
707
707
708 if (state) {
708 if (state) {
709 $showVersionDiff.attr('disabled', 'disabled');
709 $showVersionDiff.attr('disabled', 'disabled');
710 $showVersionDiff.addClass('disabled');
710 $showVersionDiff.addClass('disabled');
711 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
711 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
712 }
712 }
713 else {
713 else {
714 $showVersionDiff.removeAttr('disabled');
714 $showVersionDiff.removeAttr('disabled');
715 $showVersionDiff.removeClass('disabled');
715 $showVersionDiff.removeClass('disabled');
716
716
717 if (selectedVersion == otherVersion) {
717 if (selectedVersion == otherVersion) {
718 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
718 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
719 } else {
719 } else {
720 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
720 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
721 }
721 }
722 }
722 }
723
723
724 };
724 };
725
725
726 this.showVersionDiff = function () {
726 this.showVersionDiff = function () {
727 var target = self.$verTarget.filter(':checked');
727 var target = self.$verTarget.filter(':checked');
728 var source = self.$verSource.filter(':checked');
728 var source = self.$verSource.filter(':checked');
729
729
730 if (target.val() && source.val()) {
730 if (target.val() && source.val()) {
731 var params = {
731 var params = {
732 'pull_request_id': templateContext.pull_request_data.pull_request_id,
732 'pull_request_id': templateContext.pull_request_data.pull_request_id,
733 'repo_name': templateContext.repo_name,
733 'repo_name': templateContext.repo_name,
734 'version': target.val(),
734 'version': target.val(),
735 'from_version': source.val()
735 'from_version': source.val()
736 };
736 };
737 window.location = pyroutes.url('pullrequest_show', params)
737 window.location = pyroutes.url('pullrequest_show', params)
738 }
738 }
739
739
740 return false;
740 return false;
741 };
741 };
742
742
743 this.toggleVersionView = function (elem) {
743 this.toggleVersionView = function (elem) {
744
744
745 if (this.$showVersionDiff.is(':visible')) {
745 if (this.$showVersionDiff.is(':visible')) {
746 $('.version-pr').hide();
746 $('.version-pr').hide();
747 this.$showVersionDiff.hide();
747 this.$showVersionDiff.hide();
748 $(elem).html($(elem).data('toggleOn'))
748 $(elem).html($(elem).data('toggleOn'))
749 } else {
749 } else {
750 $('.version-pr').show();
750 $('.version-pr').show();
751 this.$showVersionDiff.show();
751 this.$showVersionDiff.show();
752 $(elem).html($(elem).data('toggleOff'))
752 $(elem).html($(elem).data('toggleOff'))
753 }
753 }
754
754
755 return false
755 return false
756 };
756 };
757
757
758 };
758 };
759
759
760
760
761 window.UpdatePrController = function () {
761 window.UpdatePrController = function () {
762 var self = this;
762 var self = this;
763 this.$updateCommits = $('#update_commits');
763 this.$updateCommits = $('#update_commits');
764 this.$updateCommitsSwitcher = $('#update_commits_switcher');
764 this.$updateCommitsSwitcher = $('#update_commits_switcher');
765
765
766 this.lockUpdateButton = function (label) {
766 this.lockUpdateButton = function (label) {
767 self.$updateCommits.attr('disabled', 'disabled');
767 self.$updateCommits.attr('disabled', 'disabled');
768 self.$updateCommitsSwitcher.attr('disabled', 'disabled');
768 self.$updateCommitsSwitcher.attr('disabled', 'disabled');
769
769
770 self.$updateCommits.addClass('disabled');
770 self.$updateCommits.addClass('disabled');
771 self.$updateCommitsSwitcher.addClass('disabled');
771 self.$updateCommitsSwitcher.addClass('disabled');
772
772
773 self.$updateCommits.removeClass('btn-primary');
773 self.$updateCommits.removeClass('btn-primary');
774 self.$updateCommitsSwitcher.removeClass('btn-primary');
774 self.$updateCommitsSwitcher.removeClass('btn-primary');
775
775
776 self.$updateCommits.text(_gettext(label));
776 self.$updateCommits.text(_gettext(label));
777 };
777 };
778
778
779 this.isUpdateLocked = function () {
779 this.isUpdateLocked = function () {
780 return self.$updateCommits.attr('disabled') !== undefined;
780 return self.$updateCommits.attr('disabled') !== undefined;
781 };
781 };
782
782
783 this.updateCommits = function (curNode) {
783 this.updateCommits = function (curNode) {
784 if (self.isUpdateLocked()) {
784 if (self.isUpdateLocked()) {
785 return
785 return
786 }
786 }
787 self.lockUpdateButton(_gettext('Updating...'));
787 self.lockUpdateButton(_gettext('Updating...'));
788 updateCommits(
788 updateCommits(
789 templateContext.repo_name,
789 templateContext.repo_name,
790 templateContext.pull_request_data.pull_request_id);
790 templateContext.pull_request_data.pull_request_id);
791 };
791 };
792
792
793 this.forceUpdateCommits = function () {
793 this.forceUpdateCommits = function () {
794 if (self.isUpdateLocked()) {
794 if (self.isUpdateLocked()) {
795 return
795 return
796 }
796 }
797 self.lockUpdateButton(_gettext('Force updating...'));
797 self.lockUpdateButton(_gettext('Force updating...'));
798 var force = true;
798 var force = true;
799 updateCommits(
799 updateCommits(
800 templateContext.repo_name,
800 templateContext.repo_name,
801 templateContext.pull_request_data.pull_request_id, force);
801 templateContext.pull_request_data.pull_request_id, force);
802 };
802 };
803 };
803 };
804
804
805
805
806 /**
806 /**
807 * Reviewer display panel
807 * Reviewer display panel
808 */
808 */
809 window.ReviewersPanel = {
809 window.ReviewersPanel = {
810 editButton: null,
810 editButton: null,
811 closeButton: null,
811 closeButton: null,
812 addButton: null,
812 addButton: null,
813 removeButtons: null,
813 removeButtons: null,
814 reviewRules: null,
814 reviewRules: null,
815 setReviewers: null,
815 setReviewers: null,
816 controller: null,
816 controller: null,
817
817
818 setSelectors: function () {
818 setSelectors: function () {
819 var self = this;
819 var self = this;
820 self.editButton = $('#open_edit_reviewers');
820 self.editButton = $('#open_edit_reviewers');
821 self.closeButton =$('#close_edit_reviewers');
821 self.closeButton =$('#close_edit_reviewers');
822 self.addButton = $('#add_reviewer');
822 self.addButton = $('#add_reviewer');
823 self.removeButtons = $('.reviewer_member_remove,.reviewer_member_mandatory_remove');
823 self.removeButtons = $('.reviewer_member_remove,.reviewer_member_mandatory_remove');
824 },
824 },
825
825
826 init: function (controller, reviewRules, setReviewers) {
826 init: function (controller, reviewRules, setReviewers) {
827 var self = this;
827 var self = this;
828 self.setSelectors();
828 self.setSelectors();
829
829
830 self.controller = controller;
830 self.controller = controller;
831 self.reviewRules = reviewRules;
831 self.reviewRules = reviewRules;
832 self.setReviewers = setReviewers;
832 self.setReviewers = setReviewers;
833
833
834 self.editButton.on('click', function (e) {
834 self.editButton.on('click', function (e) {
835 self.edit();
835 self.edit();
836 });
836 });
837 self.closeButton.on('click', function (e) {
837 self.closeButton.on('click', function (e) {
838 self.close();
838 self.close();
839 self.renderReviewers();
839 self.renderReviewers();
840 });
840 });
841
841
842 self.renderReviewers();
842 self.renderReviewers();
843
843
844 },
844 },
845
845
846 renderReviewers: function () {
846 renderReviewers: function () {
847 var self = this;
847 var self = this;
848
848
849 if (self.setReviewers.reviewers === undefined) {
849 if (self.setReviewers.reviewers === undefined) {
850 return
850 return
851 }
851 }
852 if (self.setReviewers.reviewers.length === 0) {
852 if (self.setReviewers.reviewers.length === 0) {
853 self.controller.emptyReviewersTable('<tr id="reviewer-empty-msg"><td colspan="6">No reviewers</td></tr>');
853 self.controller.emptyReviewersTable('<tr id="reviewer-empty-msg"><td colspan="6">No reviewers</td></tr>');
854 return
854 return
855 }
855 }
856
856
857 self.controller.emptyReviewersTable();
857 self.controller.emptyReviewersTable();
858
858
859 $.each(self.setReviewers.reviewers, function (key, val) {
859 $.each(self.setReviewers.reviewers, function (key, val) {
860
860
861 var member = val;
861 var member = val;
862 if (member.role === self.controller.ROLE_REVIEWER) {
862 if (member.role === self.controller.ROLE_REVIEWER) {
863 var entry = renderTemplate('reviewMemberEntry', {
863 var entry = renderTemplate('reviewMemberEntry', {
864 'member': member,
864 'member': member,
865 'mandatory': member.mandatory,
865 'mandatory': member.mandatory,
866 'role': member.role,
866 'role': member.role,
867 'reasons': member.reasons,
867 'reasons': member.reasons,
868 'allowed_to_update': member.allowed_to_update,
868 'allowed_to_update': member.allowed_to_update,
869 'review_status': member.review_status,
869 'review_status': member.review_status,
870 'review_status_label': member.review_status_label,
870 'review_status_label': member.review_status_label,
871 'user_group': member.user_group,
871 'user_group': member.user_group,
872 'create': false
872 'create': false
873 });
873 });
874
874
875 $(self.controller.$reviewMembers.selector).append(entry)
875 $(self.controller.$reviewMembers.selector).append(entry)
876 }
876 }
877 });
877 });
878
878
879 tooltipActivate();
879 tooltipActivate();
880 },
880 },
881
881
882 edit: function (event) {
882 edit: function (event) {
883 var self = this;
883 var self = this;
884 self.editButton.hide();
884 self.editButton.hide();
885 self.closeButton.show();
885 self.closeButton.show();
886 self.addButton.show();
886 self.addButton.show();
887 $(self.removeButtons.selector).css('visibility', 'visible');
887 $(self.removeButtons.selector).css('visibility', 'visible');
888 // review rules
888 // review rules
889 self.controller.loadReviewRules(this.reviewRules);
889 self.controller.loadReviewRules(this.reviewRules);
890 },
890 },
891
891
892 close: function (event) {
892 close: function (event) {
893 var self = this;
893 var self = this;
894 this.editButton.show();
894 this.editButton.show();
895 this.closeButton.hide();
895 this.closeButton.hide();
896 this.addButton.hide();
896 this.addButton.hide();
897 $(this.removeButtons.selector).css('visibility', 'hidden');
897 $(this.removeButtons.selector).css('visibility', 'hidden');
898 // hide review rules
898 // hide review rules
899 self.controller.hideReviewRules();
899 self.controller.hideReviewRules();
900 }
900 }
901 };
901 };
902
902
903 /**
903 /**
904 * Reviewer display panel
904 * Reviewer display panel
905 */
905 */
906 window.ObserversPanel = {
906 window.ObserversPanel = {
907 editButton: null,
907 editButton: null,
908 closeButton: null,
908 closeButton: null,
909 addButton: null,
909 addButton: null,
910 removeButtons: null,
910 removeButtons: null,
911 reviewRules: null,
911 reviewRules: null,
912 setReviewers: null,
912 setReviewers: null,
913 controller: null,
913 controller: null,
914
914
915 setSelectors: function () {
915 setSelectors: function () {
916 var self = this;
916 var self = this;
917 self.editButton = $('#open_edit_observers');
917 self.editButton = $('#open_edit_observers');
918 self.closeButton =$('#close_edit_observers');
918 self.closeButton =$('#close_edit_observers');
919 self.addButton = $('#add_observer');
919 self.addButton = $('#add_observer');
920 self.removeButtons = $('.observer_member_remove,.observer_member_mandatory_remove');
920 self.removeButtons = $('.observer_member_remove,.observer_member_mandatory_remove');
921 },
921 },
922
922
923 init: function (controller, reviewRules, setReviewers) {
923 init: function (controller, reviewRules, setReviewers) {
924 var self = this;
924 var self = this;
925 self.setSelectors();
925 self.setSelectors();
926
926
927 self.controller = controller;
927 self.controller = controller;
928 self.reviewRules = reviewRules;
928 self.reviewRules = reviewRules;
929 self.setReviewers = setReviewers;
929 self.setReviewers = setReviewers;
930
930
931 self.editButton.on('click', function (e) {
931 self.editButton.on('click', function (e) {
932 self.edit();
932 self.edit();
933 });
933 });
934 self.closeButton.on('click', function (e) {
934 self.closeButton.on('click', function (e) {
935 self.close();
935 self.close();
936 self.renderObservers();
936 self.renderObservers();
937 });
937 });
938
938
939 self.renderObservers();
939 self.renderObservers();
940
940
941 },
941 },
942
942
943 renderObservers: function () {
943 renderObservers: function () {
944 var self = this;
944 var self = this;
945 if (self.setReviewers.observers === undefined) {
945 if (self.setReviewers.observers === undefined) {
946 return
946 return
947 }
947 }
948 if (self.setReviewers.observers.length === 0) {
948 if (self.setReviewers.observers.length === 0) {
949 self.controller.emptyObserversTable('<tr id="observer-empty-msg"><td colspan="6">No observers</td></tr>');
949 self.controller.emptyObserversTable('<tr id="observer-empty-msg"><td colspan="6">No observers</td></tr>');
950 return
950 return
951 }
951 }
952
952
953 self.controller.emptyObserversTable();
953 self.controller.emptyObserversTable();
954
954
955 $.each(self.setReviewers.observers, function (key, val) {
955 $.each(self.setReviewers.observers, function (key, val) {
956 var member = val;
956 var member = val;
957 if (member.role === self.controller.ROLE_OBSERVER) {
957 if (member.role === self.controller.ROLE_OBSERVER) {
958 var entry = renderTemplate('reviewMemberEntry', {
958 var entry = renderTemplate('reviewMemberEntry', {
959 'member': member,
959 'member': member,
960 'mandatory': member.mandatory,
960 'mandatory': member.mandatory,
961 'role': member.role,
961 'role': member.role,
962 'reasons': member.reasons,
962 'reasons': member.reasons,
963 'allowed_to_update': member.allowed_to_update,
963 'allowed_to_update': member.allowed_to_update,
964 'review_status': member.review_status,
964 'review_status': member.review_status,
965 'review_status_label': member.review_status_label,
965 'review_status_label': member.review_status_label,
966 'user_group': member.user_group,
966 'user_group': member.user_group,
967 'create': false
967 'create': false
968 });
968 });
969
969
970 $(self.controller.$observerMembers.selector).append(entry)
970 $(self.controller.$observerMembers.selector).append(entry)
971 }
971 }
972 });
972 });
973
973
974 tooltipActivate();
974 tooltipActivate();
975 },
975 },
976
976
977 edit: function (event) {
977 edit: function (event) {
978 this.editButton.hide();
978 this.editButton.hide();
979 this.closeButton.show();
979 this.closeButton.show();
980 this.addButton.show();
980 this.addButton.show();
981 $(this.removeButtons.selector).css('visibility', 'visible');
981 $(this.removeButtons.selector).css('visibility', 'visible');
982 },
982 },
983
983
984 close: function (event) {
984 close: function (event) {
985 this.editButton.show();
985 this.editButton.show();
986 this.closeButton.hide();
986 this.closeButton.hide();
987 this.addButton.hide();
987 this.addButton.hide();
988 $(this.removeButtons.selector).css('visibility', 'hidden');
988 $(this.removeButtons.selector).css('visibility', 'hidden');
989 }
989 }
990
990
991 };
991 };
992
992
993 window.PRDetails = {
993 window.PRDetails = {
994 editButton: null,
994 editButton: null,
995 closeButton: null,
995 closeButton: null,
996 deleteButton: null,
996 deleteButton: null,
997 viewFields: null,
997 viewFields: null,
998 editFields: null,
998 editFields: null,
999
999
1000 setSelectors: function () {
1000 setSelectors: function () {
1001 var self = this;
1001 var self = this;
1002 self.editButton = $('#open_edit_pullrequest')
1002 self.editButton = $('#open_edit_pullrequest')
1003 self.closeButton = $('#close_edit_pullrequest')
1003 self.closeButton = $('#close_edit_pullrequest')
1004 self.deleteButton = $('#delete_pullrequest')
1004 self.deleteButton = $('#delete_pullrequest')
1005 self.viewFields = $('#pr-desc, #pr-title')
1005 self.viewFields = $('#pr-desc, #pr-title')
1006 self.editFields = $('#pr-desc-edit, #pr-title-edit, .pr-save')
1006 self.editFields = $('#pr-desc-edit, #pr-title-edit, .pr-save')
1007 },
1007 },
1008
1008
1009 init: function () {
1009 init: function () {
1010 var self = this;
1010 var self = this;
1011 self.setSelectors();
1011 self.setSelectors();
1012 self.editButton.on('click', function (e) {
1012 self.editButton.on('click', function (e) {
1013 self.edit();
1013 self.edit();
1014 });
1014 });
1015 self.closeButton.on('click', function (e) {
1015 self.closeButton.on('click', function (e) {
1016 self.view();
1016 self.view();
1017 });
1017 });
1018 },
1018 },
1019
1019
1020 edit: function (event) {
1020 edit: function (event) {
1021 var cmInstance = $('#pr-description-input').get(0).MarkupForm.cm;
1021 var cmInstance = $('#pr-description-input').get(0).MarkupForm.cm;
1022 this.viewFields.hide();
1022 this.viewFields.hide();
1023 this.editButton.hide();
1023 this.editButton.hide();
1024 this.deleteButton.hide();
1024 this.deleteButton.hide();
1025 this.closeButton.show();
1025 this.closeButton.show();
1026 this.editFields.show();
1026 this.editFields.show();
1027 cmInstance.refresh();
1027 cmInstance.refresh();
1028 },
1028 },
1029
1029
1030 view: function (event) {
1030 view: function (event) {
1031 this.editButton.show();
1031 this.editButton.show();
1032 this.deleteButton.show();
1032 this.deleteButton.show();
1033 this.editFields.hide();
1033 this.editFields.hide();
1034 this.closeButton.hide();
1034 this.closeButton.hide();
1035 this.viewFields.show();
1035 this.viewFields.show();
1036 }
1036 }
1037 };
1037 };
1038
1038
1039 /**
1039 /**
1040 * OnLine presence using channelstream
1040 * OnLine presence using channelstream
1041 */
1041 */
1042 window.ReviewerPresenceController = function (channel) {
1042 window.ReviewerPresenceController = function (channel) {
1043 var self = this;
1043 var self = this;
1044 this.channel = channel;
1044 this.channel = channel;
1045 this.users = {};
1045 this.users = {};
1046
1046
1047 this.storeUsers = function (users) {
1047 this.storeUsers = function (users) {
1048 self.users = {}
1048 self.users = {}
1049 $.each(users, function (index, value) {
1049 $.each(users, function (index, value) {
1050 var userId = value.state.id;
1050 var userId = value.state.id;
1051 self.users[userId] = value.state;
1051 self.users[userId] = value.state;
1052 })
1052 })
1053 }
1053 }
1054
1054
1055 this.render = function () {
1055 this.render = function () {
1056 $.each($('.reviewer_entry'), function (index, value) {
1056 $.each($('.reviewer_entry'), function (index, value) {
1057 var userData = $(value).data();
1057 var userData = $(value).data();
1058 if (self.users[userData.reviewerUserId] !== undefined) {
1058 if (self.users[userData.reviewerUserId] !== undefined) {
1059 $(value).find('.presence-state').show();
1059 $(value).find('.presence-state').show();
1060 } else {
1060 } else {
1061 $(value).find('.presence-state').hide();
1061 $(value).find('.presence-state').hide();
1062 }
1062 }
1063 })
1063 })
1064 };
1064 };
1065
1065
1066 this.handlePresence = function (data) {
1066 this.handlePresence = function (data) {
1067 if (data.type == 'presence' && data.channel === self.channel) {
1067 if (data.type == 'presence' && data.channel === self.channel) {
1068 this.storeUsers(data.users);
1068 this.storeUsers(data.users);
1069 this.render()
1069 this.render()
1070 }
1070 }
1071 };
1071 };
1072
1072
1073 this.handleChannelUpdate = function (data) {
1073 this.handleChannelUpdate = function (data) {
1074 if (data.channel === this.channel) {
1074 if (data.channel === this.channel) {
1075 this.storeUsers(data.state.users);
1075 this.storeUsers(data.state.users);
1076 this.render()
1076 this.render()
1077 }
1077 }
1078
1078
1079 };
1079 };
1080
1080
1081 /* subscribe to the current presence */
1081 /* subscribe to the current presence */
1082 $.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
1082 $.Topic('/connection_controller/presence').subscribe(this.handlePresence.bind(this));
1083 /* subscribe to updates e.g connect/disconnect */
1083 /* subscribe to updates e.g connect/disconnect */
1084 $.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
1084 $.Topic('/connection_controller/channel_update').subscribe(this.handleChannelUpdate.bind(this));
1085
1085
1086 };
1086 };
1087
1087
1088 window.refreshComments = function (version) {
1088 window.refreshComments = function (version) {
1089 version = version || templateContext.pull_request_data.pull_request_version || '';
1089 version = version || templateContext.pull_request_data.pull_request_version || '';
1090
1090
1091 // Pull request case
1091 // Pull request case
1092 if (templateContext.pull_request_data.pull_request_id !== null) {
1092 if (templateContext.pull_request_data.pull_request_id !== null) {
1093 var params = {
1093 var params = {
1094 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1094 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1095 'repo_name': templateContext.repo_name,
1095 'repo_name': templateContext.repo_name,
1096 'version': version,
1096 'version': version,
1097 };
1097 };
1098 var loadUrl = pyroutes.url('pullrequest_comments', params);
1098 var loadUrl = pyroutes.url('pullrequest_comments', params);
1099 } // commit case
1099 } // commit case
1100 else {
1100 else {
1101 return
1101 return
1102 }
1102 }
1103
1103
1104 var currentIDs = []
1104 var currentIDs = []
1105 $.each($('.comment'), function (idx, element) {
1105 $.each($('.comment'), function (idx, element) {
1106 currentIDs.push($(element).data('commentId'));
1106 currentIDs.push($(element).data('commentId'));
1107 });
1107 });
1108 var data = {"comments": currentIDs};
1108 var data = {"comments": currentIDs};
1109
1109
1110 var $targetElem = $('.comments-content-table');
1110 var $targetElem = $('.comments-content-table');
1111 $targetElem.css('opacity', 0.3);
1111 $targetElem.css('opacity', 0.3);
1112
1112
1113 var success = function (data) {
1113 var success = function (data) {
1114 var $counterElem = $('#comments-count');
1114 var $counterElem = $('#comments-count');
1115 var newCount = $(data).data('counter');
1115 var newCount = $(data).data('counter');
1116 if (newCount !== undefined) {
1116 if (newCount !== undefined) {
1117 var callback = function () {
1117 var callback = function () {
1118 $counterElem.animate({'opacity': 1.00}, 200)
1118 $counterElem.animate({'opacity': 1.00}, 200)
1119 $counterElem.html(newCount);
1119 $counterElem.html(newCount);
1120 };
1120 };
1121 $counterElem.animate({'opacity': 0.15}, 200, callback);
1121 $counterElem.animate({'opacity': 0.15}, 200, callback);
1122 }
1122 }
1123
1123
1124 $targetElem.css('opacity', 1);
1124 $targetElem.css('opacity', 1);
1125 $targetElem.html(data);
1125 $targetElem.html(data);
1126 tooltipActivate();
1126 tooltipActivate();
1127 }
1127 }
1128
1128
1129 ajaxPOST(loadUrl, data, success, null, {})
1129 ajaxPOST(loadUrl, data, success, null, {})
1130
1130
1131 }
1131 }
1132
1132
1133 window.refreshTODOs = function (version) {
1133 window.refreshTODOs = function (version) {
1134 version = version || templateContext.pull_request_data.pull_request_version || '';
1134 version = version || templateContext.pull_request_data.pull_request_version || '';
1135 // Pull request case
1135 // Pull request case
1136 if (templateContext.pull_request_data.pull_request_id !== null) {
1136 if (templateContext.pull_request_data.pull_request_id !== null) {
1137 var params = {
1137 var params = {
1138 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1138 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1139 'repo_name': templateContext.repo_name,
1139 'repo_name': templateContext.repo_name,
1140 'version': version,
1140 'version': version,
1141 };
1141 };
1142 var loadUrl = pyroutes.url('pullrequest_comments', params);
1142 var loadUrl = pyroutes.url('pullrequest_todos', params);
1143 } // commit case
1143 } // commit case
1144 else {
1144 else {
1145 return
1145 return
1146 }
1146 }
1147
1147
1148 var currentIDs = []
1148 var currentIDs = []
1149 $.each($('.comment'), function (idx, element) {
1149 $.each($('.comment'), function (idx, element) {
1150 currentIDs.push($(element).data('commentId'));
1150 currentIDs.push($(element).data('commentId'));
1151 });
1151 });
1152
1152
1153 var data = {"comments": currentIDs};
1153 var data = {"comments": currentIDs};
1154 var $targetElem = $('.todos-content-table');
1154 var $targetElem = $('.todos-content-table');
1155 $targetElem.css('opacity', 0.3);
1155 $targetElem.css('opacity', 0.3);
1156
1156
1157 var success = function (data) {
1157 var success = function (data) {
1158 var $counterElem = $('#todos-count')
1158 var $counterElem = $('#todos-count')
1159 var newCount = $(data).data('counter');
1159 var newCount = $(data).data('counter');
1160 if (newCount !== undefined) {
1160 if (newCount !== undefined) {
1161 var callback = function () {
1161 var callback = function () {
1162 $counterElem.animate({'opacity': 1.00}, 200)
1162 $counterElem.animate({'opacity': 1.00}, 200)
1163 $counterElem.html(newCount);
1163 $counterElem.html(newCount);
1164 };
1164 };
1165 $counterElem.animate({'opacity': 0.15}, 200, callback);
1165 $counterElem.animate({'opacity': 0.15}, 200, callback);
1166 }
1166 }
1167
1167
1168 $targetElem.css('opacity', 1);
1168 $targetElem.css('opacity', 1);
1169 $targetElem.html(data);
1169 $targetElem.html(data);
1170 tooltipActivate();
1170 tooltipActivate();
1171 }
1171 }
1172
1172
1173 ajaxPOST(loadUrl, data, success, null, {})
1173 ajaxPOST(loadUrl, data, success, null, {})
1174
1174
1175 }
1175 }
1176
1176
1177 window.refreshAllComments = function (version) {
1177 window.refreshAllComments = function (version) {
1178 version = version || templateContext.pull_request_data.pull_request_version || '';
1178 version = version || templateContext.pull_request_data.pull_request_version || '';
1179
1179
1180 refreshComments(version);
1180 refreshComments(version);
1181 refreshTODOs(version);
1181 refreshTODOs(version);
1182 };
1182 };
1183
1183
1184 window.sidebarComment = function (commentId) {
1184 window.sidebarComment = function (commentId) {
1185 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1185 var jsonData = $('#commentHovercard{0}'.format(commentId)).data('commentJsonB64');
1186 if (!jsonData) {
1186 if (!jsonData) {
1187 return 'Failed to load comment {0}'.format(commentId)
1187 return 'Failed to load comment {0}'.format(commentId)
1188 }
1188 }
1189 var funcData = JSON.parse(atob(jsonData));
1189 var funcData = JSON.parse(atob(jsonData));
1190 return renderTemplate('sideBarCommentHovercard', funcData)
1190 return renderTemplate('sideBarCommentHovercard', funcData)
1191 };
1191 };
General Comments 0
You need to be logged in to leave comments. Login now