##// END OF EJS Templates
default-reviewers: fixed edit mode when creating new entries.
marcink -
r2504:dc37941f default
parent child Browse files
Show More
@@ -1,586 +1,587 b''
1 // # Copyright (C) 2010-2018 RhodeCode GmbH
1 // # Copyright (C) 2010-2018 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 $('#save').attr('disabled', 'disabled');
44 $('#save').attr('disabled', 'disabled');
45 }
45 }
46 else if (checksMeet) {
46 else if (checksMeet) {
47 $('#save').removeAttr('disabled');
47 $('#save').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(sourceRef, elements, limit) {
73 var getTitleAndDescription = function(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).find('td.td-description .message').data('messageRaw');
78 var rawMessage = $(value).find('td.td-description .message').data('messageRaw');
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 title = $(elements[0]).find('td.td-description .message').data('messageRaw').split('\n')[0];
83 title = $(elements[0]).find('td.td-description .message').data('messageRaw').split('\n')[0];
84 }
84 }
85 else {
85 else {
86 // use reference name
86 // use reference name
87 title = sourceRef.replace(/-/g, ' ').replace(/_/g, ' ').capitalizeFirstLetter();
87 title = sourceRef.replace(/-/g, ' ').replace(/_/g, ' ').capitalizeFirstLetter();
88 }
88 }
89
89
90 return [title, desc]
90 return [title, desc]
91 };
91 };
92
92
93
93
94
94
95 ReviewersController = function () {
95 ReviewersController = function () {
96 var self = this;
96 var self = this;
97 this.$reviewRulesContainer = $('#review_rules');
97 this.$reviewRulesContainer = $('#review_rules');
98 this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules');
98 this.$rulesList = this.$reviewRulesContainer.find('.pr-reviewer-rules');
99 this.forbidReviewUsers = undefined;
99 this.forbidReviewUsers = undefined;
100 this.$reviewMembers = $('#review_members');
100 this.$reviewMembers = $('#review_members');
101 this.currentRequest = null;
101 this.currentRequest = null;
102
102
103 this.defaultForbidReviewUsers = function() {
103 this.defaultForbidReviewUsers = function() {
104 return [
104 return [
105 {'username': 'default',
105 {'username': 'default',
106 'user_id': templateContext.default_user.user_id}
106 'user_id': templateContext.default_user.user_id}
107 ];
107 ];
108 };
108 };
109
109
110 this.hideReviewRules = function() {
110 this.hideReviewRules = function() {
111 self.$reviewRulesContainer.hide();
111 self.$reviewRulesContainer.hide();
112 };
112 };
113
113
114 this.showReviewRules = function() {
114 this.showReviewRules = function() {
115 self.$reviewRulesContainer.show();
115 self.$reviewRulesContainer.show();
116 };
116 };
117
117
118 this.addRule = function(ruleText) {
118 this.addRule = function(ruleText) {
119 self.showReviewRules();
119 self.showReviewRules();
120 return '<div>- {0}</div>'.format(ruleText)
120 return '<div>- {0}</div>'.format(ruleText)
121 };
121 };
122
122
123 this.loadReviewRules = function(data) {
123 this.loadReviewRules = function(data) {
124 // reset forbidden Users
124 // reset forbidden Users
125 this.forbidReviewUsers = self.defaultForbidReviewUsers();
125 this.forbidReviewUsers = self.defaultForbidReviewUsers();
126
126
127 // reset state of review rules
127 // reset state of review rules
128 self.$rulesList.html('');
128 self.$rulesList.html('');
129
129
130 if (!data || data.rules === undefined || $.isEmptyObject(data.rules)) {
130 if (!data || data.rules === undefined || $.isEmptyObject(data.rules)) {
131 // default rule, case for older repo that don't have any rules stored
131 // default rule, case for older repo that don't have any rules stored
132 self.$rulesList.append(
132 self.$rulesList.append(
133 self.addRule(
133 self.addRule(
134 _gettext('All reviewers must vote.'))
134 _gettext('All reviewers must vote.'))
135 );
135 );
136 return self.forbidReviewUsers
136 return self.forbidReviewUsers
137 }
137 }
138
138
139 if (data.rules.voting !== undefined) {
139 if (data.rules.voting !== undefined) {
140 if (data.rules.voting < 0) {
140 if (data.rules.voting < 0) {
141 self.$rulesList.append(
141 self.$rulesList.append(
142 self.addRule(
142 self.addRule(
143 _gettext('All individual reviewers must vote.'))
143 _gettext('All individual reviewers must vote.'))
144 )
144 )
145 } else if (data.rules.voting === 1) {
145 } else if (data.rules.voting === 1) {
146 self.$rulesList.append(
146 self.$rulesList.append(
147 self.addRule(
147 self.addRule(
148 _gettext('At least {0} reviewer must vote.').format(data.rules.voting))
148 _gettext('At least {0} reviewer must vote.').format(data.rules.voting))
149 )
149 )
150
150
151 } else {
151 } else {
152 self.$rulesList.append(
152 self.$rulesList.append(
153 self.addRule(
153 self.addRule(
154 _gettext('At least {0} reviewers must vote.').format(data.rules.voting))
154 _gettext('At least {0} reviewers must vote.').format(data.rules.voting))
155 )
155 )
156 }
156 }
157 }
157 }
158
158
159 if (data.rules.voting_groups !== undefined) {
159 if (data.rules.voting_groups !== undefined) {
160 $.each(data.rules.voting_groups, function(index, rule_data) {
160 $.each(data.rules.voting_groups, function(index, rule_data) {
161 self.$rulesList.append(
161 self.$rulesList.append(
162 self.addRule(rule_data.text)
162 self.addRule(rule_data.text)
163 )
163 )
164 });
164 });
165 }
165 }
166
166
167 if (data.rules.use_code_authors_for_review) {
167 if (data.rules.use_code_authors_for_review) {
168 self.$rulesList.append(
168 self.$rulesList.append(
169 self.addRule(
169 self.addRule(
170 _gettext('Reviewers picked from source code changes.'))
170 _gettext('Reviewers picked from source code changes.'))
171 )
171 )
172 }
172 }
173 if (data.rules.forbid_adding_reviewers) {
173 if (data.rules.forbid_adding_reviewers) {
174 $('#add_reviewer_input').remove();
174 $('#add_reviewer_input').remove();
175 self.$rulesList.append(
175 self.$rulesList.append(
176 self.addRule(
176 self.addRule(
177 _gettext('Adding new reviewers is forbidden.'))
177 _gettext('Adding new reviewers is forbidden.'))
178 )
178 )
179 }
179 }
180 if (data.rules.forbid_author_to_review) {
180 if (data.rules.forbid_author_to_review) {
181 self.forbidReviewUsers.push(data.rules_data.pr_author);
181 self.forbidReviewUsers.push(data.rules_data.pr_author);
182 self.$rulesList.append(
182 self.$rulesList.append(
183 self.addRule(
183 self.addRule(
184 _gettext('Author is not allowed to be a reviewer.'))
184 _gettext('Author is not allowed to be a reviewer.'))
185 )
185 )
186 }
186 }
187 if (data.rules.forbid_commit_author_to_review) {
187 if (data.rules.forbid_commit_author_to_review) {
188
188
189 if (data.rules_data.forbidden_users) {
189 if (data.rules_data.forbidden_users) {
190 $.each(data.rules_data.forbidden_users, function(index, member_data) {
190 $.each(data.rules_data.forbidden_users, function(index, member_data) {
191 self.forbidReviewUsers.push(member_data)
191 self.forbidReviewUsers.push(member_data)
192 });
192 });
193
193
194 }
194 }
195
195
196 self.$rulesList.append(
196 self.$rulesList.append(
197 self.addRule(
197 self.addRule(
198 _gettext('Commit Authors are not allowed to be a reviewer.'))
198 _gettext('Commit Authors are not allowed to be a reviewer.'))
199 )
199 )
200 }
200 }
201
201
202 return self.forbidReviewUsers
202 return self.forbidReviewUsers
203 };
203 };
204
204
205 this.loadDefaultReviewers = function(sourceRepo, sourceRef, targetRepo, targetRef) {
205 this.loadDefaultReviewers = function(sourceRepo, sourceRef, targetRepo, targetRef) {
206
206
207 if (self.currentRequest) {
207 if (self.currentRequest) {
208 // make sure we cleanup old running requests before triggering this
208 // make sure we cleanup old running requests before triggering this
209 // again
209 // again
210 self.currentRequest.abort();
210 self.currentRequest.abort();
211 }
211 }
212
212
213 $('.calculate-reviewers').show();
213 $('.calculate-reviewers').show();
214 // reset reviewer members
214 // reset reviewer members
215 self.$reviewMembers.empty();
215 self.$reviewMembers.empty();
216
216
217 prButtonLock(true, null, 'reviewers');
217 prButtonLock(true, null, 'reviewers');
218 $('#user').hide(); // hide user autocomplete before load
218 $('#user').hide(); // hide user autocomplete before load
219
219
220 var url = pyroutes.url('repo_default_reviewers_data',
220 var url = pyroutes.url('repo_default_reviewers_data',
221 {
221 {
222 'repo_name': templateContext.repo_name,
222 'repo_name': templateContext.repo_name,
223 'source_repo': sourceRepo,
223 'source_repo': sourceRepo,
224 'source_ref': sourceRef[2],
224 'source_ref': sourceRef[2],
225 'target_repo': targetRepo,
225 'target_repo': targetRepo,
226 'target_ref': targetRef[2]
226 'target_ref': targetRef[2]
227 });
227 });
228
228
229 self.currentRequest = $.get(url)
229 self.currentRequest = $.get(url)
230 .done(function(data) {
230 .done(function(data) {
231 self.currentRequest = null;
231 self.currentRequest = null;
232
232
233 // review rules
233 // review rules
234 self.loadReviewRules(data);
234 self.loadReviewRules(data);
235
235
236 for (var i = 0; i < data.reviewers.length; i++) {
236 for (var i = 0; i < data.reviewers.length; i++) {
237 var reviewer = data.reviewers[i];
237 var reviewer = data.reviewers[i];
238 self.addReviewMember(
238 self.addReviewMember(
239 reviewer, reviewer.reasons, reviewer.mandatory);
239 reviewer, reviewer.reasons, reviewer.mandatory);
240 }
240 }
241 $('.calculate-reviewers').hide();
241 $('.calculate-reviewers').hide();
242 prButtonLock(false, null, 'reviewers');
242 prButtonLock(false, null, 'reviewers');
243 $('#user').show(); // show user autocomplete after load
243 $('#user').show(); // show user autocomplete after load
244 });
244 });
245 };
245 };
246
246
247 // check those, refactor
247 // check those, refactor
248 this.removeReviewMember = function(reviewer_id, mark_delete) {
248 this.removeReviewMember = function(reviewer_id, mark_delete) {
249 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
249 var reviewer = $('#reviewer_{0}'.format(reviewer_id));
250
250
251 if(typeof(mark_delete) === undefined){
251 if(typeof(mark_delete) === undefined){
252 mark_delete = false;
252 mark_delete = false;
253 }
253 }
254
254
255 if(mark_delete === true){
255 if(mark_delete === true){
256 if (reviewer){
256 if (reviewer){
257 // now delete the input
257 // now delete the input
258 $('#reviewer_{0} input'.format(reviewer_id)).remove();
258 $('#reviewer_{0} input'.format(reviewer_id)).remove();
259 // mark as to-delete
259 // mark as to-delete
260 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
260 var obj = $('#reviewer_{0}_name'.format(reviewer_id));
261 obj.addClass('to-delete');
261 obj.addClass('to-delete');
262 obj.css({"text-decoration":"line-through", "opacity": 0.5});
262 obj.css({"text-decoration":"line-through", "opacity": 0.5});
263 }
263 }
264 }
264 }
265 else{
265 else{
266 $('#reviewer_{0}'.format(reviewer_id)).remove();
266 $('#reviewer_{0}'.format(reviewer_id)).remove();
267 }
267 }
268 };
268 };
269 this.reviewMemberEntry = function() {
269 this.reviewMemberEntry = function() {
270
270
271 };
271 };
272 this.addReviewMember = function(reviewer_obj, reasons, mandatory) {
272 this.addReviewMember = function(reviewer_obj, reasons, mandatory) {
273 var members = self.$reviewMembers.get(0);
273 var members = self.$reviewMembers.get(0);
274 var id = reviewer_obj.user_id;
274 var id = reviewer_obj.user_id;
275 var username = reviewer_obj.username;
275 var username = reviewer_obj.username;
276
276
277 var reasons = reasons || [];
277 var reasons = reasons || [];
278 var mandatory = mandatory || false;
278 var mandatory = mandatory || false;
279
279
280 // register IDS to check if we don't have this ID already in
280 // register IDS to check if we don't have this ID already in
281 var currentIds = [];
281 var currentIds = [];
282 var _els = self.$reviewMembers.find('li').toArray();
282 var _els = self.$reviewMembers.find('li').toArray();
283 for (el in _els){
283 for (el in _els){
284 currentIds.push(_els[el].id)
284 currentIds.push(_els[el].id)
285 }
285 }
286
286
287 var userAllowedReview = function(userId) {
287 var userAllowedReview = function(userId) {
288 var allowed = true;
288 var allowed = true;
289 $.each(self.forbidReviewUsers, function(index, member_data) {
289 $.each(self.forbidReviewUsers, function(index, member_data) {
290 if (parseInt(userId) === member_data['user_id']) {
290 if (parseInt(userId) === member_data['user_id']) {
291 allowed = false;
291 allowed = false;
292 return false // breaks the loop
292 return false // breaks the loop
293 }
293 }
294 });
294 });
295 return allowed
295 return allowed
296 };
296 };
297
297
298 var userAllowed = userAllowedReview(id);
298 var userAllowed = userAllowedReview(id);
299 if (!userAllowed){
299 if (!userAllowed){
300 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
300 alert(_gettext('User `{0}` not allowed to be a reviewer').format(username));
301 } else {
301 } else {
302 // only add if it's not there
302 // only add if it's not there
303 var alreadyReviewer = currentIds.indexOf('reviewer_'+id) != -1;
303 var alreadyReviewer = currentIds.indexOf('reviewer_'+id) != -1;
304
304
305 if (alreadyReviewer) {
305 if (alreadyReviewer) {
306 alert(_gettext('User `{0}` already in reviewers').format(username));
306 alert(_gettext('User `{0}` already in reviewers').format(username));
307 } else {
307 } else {
308 members.innerHTML += renderTemplate('reviewMemberEntry', {
308 members.innerHTML += renderTemplate('reviewMemberEntry', {
309 'member': reviewer_obj,
309 'member': reviewer_obj,
310 'mandatory': mandatory,
310 'mandatory': mandatory,
311 'allowed_to_update': true,
311 'allowed_to_update': true,
312 'review_status': 'not_reviewed',
312 'review_status': 'not_reviewed',
313 'review_status_label': _gettext('Not Reviewed'),
313 'review_status_label': _gettext('Not Reviewed'),
314 'reasons': reasons
314 'reasons': reasons,
315 'create': true
315 });
316 });
316 }
317 }
317 }
318 }
318
319
319 };
320 };
320
321
321 this.updateReviewers = function(repo_name, pull_request_id){
322 this.updateReviewers = function(repo_name, pull_request_id){
322 var postData = $('#reviewers input').serialize();
323 var postData = $('#reviewers input').serialize();
323 _updatePullRequest(repo_name, pull_request_id, postData);
324 _updatePullRequest(repo_name, pull_request_id, postData);
324 };
325 };
325
326
326 };
327 };
327
328
328
329
329 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
330 var _updatePullRequest = function(repo_name, pull_request_id, postData) {
330 var url = pyroutes.url(
331 var url = pyroutes.url(
331 'pullrequest_update',
332 'pullrequest_update',
332 {"repo_name": repo_name, "pull_request_id": pull_request_id});
333 {"repo_name": repo_name, "pull_request_id": pull_request_id});
333 if (typeof postData === 'string' ) {
334 if (typeof postData === 'string' ) {
334 postData += '&csrf_token=' + CSRF_TOKEN;
335 postData += '&csrf_token=' + CSRF_TOKEN;
335 } else {
336 } else {
336 postData.csrf_token = CSRF_TOKEN;
337 postData.csrf_token = CSRF_TOKEN;
337 }
338 }
338 var success = function(o) {
339 var success = function(o) {
339 window.location.reload();
340 window.location.reload();
340 };
341 };
341 ajaxPOST(url, postData, success);
342 ajaxPOST(url, postData, success);
342 };
343 };
343
344
344 /**
345 /**
345 * PULL REQUEST update commits
346 * PULL REQUEST update commits
346 */
347 */
347 var updateCommits = function(repo_name, pull_request_id) {
348 var updateCommits = function(repo_name, pull_request_id) {
348 var postData = {
349 var postData = {
349 'update_commits': true};
350 'update_commits': true};
350 _updatePullRequest(repo_name, pull_request_id, postData);
351 _updatePullRequest(repo_name, pull_request_id, postData);
351 };
352 };
352
353
353
354
354 /**
355 /**
355 * PULL REQUEST edit info
356 * PULL REQUEST edit info
356 */
357 */
357 var editPullRequest = function(repo_name, pull_request_id, title, description) {
358 var editPullRequest = function(repo_name, pull_request_id, title, description) {
358 var url = pyroutes.url(
359 var url = pyroutes.url(
359 'pullrequest_update',
360 'pullrequest_update',
360 {"repo_name": repo_name, "pull_request_id": pull_request_id});
361 {"repo_name": repo_name, "pull_request_id": pull_request_id});
361
362
362 var postData = {
363 var postData = {
363 'title': title,
364 'title': title,
364 'description': description,
365 'description': description,
365 'edit_pull_request': true,
366 'edit_pull_request': true,
366 'csrf_token': CSRF_TOKEN
367 'csrf_token': CSRF_TOKEN
367 };
368 };
368 var success = function(o) {
369 var success = function(o) {
369 window.location.reload();
370 window.location.reload();
370 };
371 };
371 ajaxPOST(url, postData, success);
372 ajaxPOST(url, postData, success);
372 };
373 };
373
374
374 var initPullRequestsCodeMirror = function (textAreaId) {
375 var initPullRequestsCodeMirror = function (textAreaId) {
375 var ta = $(textAreaId).get(0);
376 var ta = $(textAreaId).get(0);
376 var initialHeight = '100px';
377 var initialHeight = '100px';
377
378
378 // default options
379 // default options
379 var codeMirrorOptions = {
380 var codeMirrorOptions = {
380 mode: "text",
381 mode: "text",
381 lineNumbers: false,
382 lineNumbers: false,
382 indentUnit: 4,
383 indentUnit: 4,
383 theme: 'rc-input'
384 theme: 'rc-input'
384 };
385 };
385
386
386 var codeMirrorInstance = CodeMirror.fromTextArea(ta, codeMirrorOptions);
387 var codeMirrorInstance = CodeMirror.fromTextArea(ta, codeMirrorOptions);
387 // marker for manually set description
388 // marker for manually set description
388 codeMirrorInstance._userDefinedDesc = false;
389 codeMirrorInstance._userDefinedDesc = false;
389 codeMirrorInstance.setSize(null, initialHeight);
390 codeMirrorInstance.setSize(null, initialHeight);
390 codeMirrorInstance.on("change", function(instance, changeObj) {
391 codeMirrorInstance.on("change", function(instance, changeObj) {
391 var height = initialHeight;
392 var height = initialHeight;
392 var lines = instance.lineCount();
393 var lines = instance.lineCount();
393 if (lines > 6 && lines < 20) {
394 if (lines > 6 && lines < 20) {
394 height = "auto"
395 height = "auto"
395 }
396 }
396 else if (lines >= 20) {
397 else if (lines >= 20) {
397 height = 20 * 15;
398 height = 20 * 15;
398 }
399 }
399 instance.setSize(null, height);
400 instance.setSize(null, height);
400
401
401 // detect if the change was trigger by auto desc, or user input
402 // detect if the change was trigger by auto desc, or user input
402 changeOrigin = changeObj.origin;
403 changeOrigin = changeObj.origin;
403
404
404 if (changeOrigin === "setValue") {
405 if (changeOrigin === "setValue") {
405 cmLog.debug('Change triggered by setValue');
406 cmLog.debug('Change triggered by setValue');
406 }
407 }
407 else {
408 else {
408 cmLog.debug('user triggered change !');
409 cmLog.debug('user triggered change !');
409 // set special marker to indicate user has created an input.
410 // set special marker to indicate user has created an input.
410 instance._userDefinedDesc = true;
411 instance._userDefinedDesc = true;
411 }
412 }
412
413
413 });
414 });
414
415
415 return codeMirrorInstance
416 return codeMirrorInstance
416 };
417 };
417
418
418 /**
419 /**
419 * Reviewer autocomplete
420 * Reviewer autocomplete
420 */
421 */
421 var ReviewerAutoComplete = function(inputId) {
422 var ReviewerAutoComplete = function(inputId) {
422 $(inputId).autocomplete({
423 $(inputId).autocomplete({
423 serviceUrl: pyroutes.url('user_autocomplete_data'),
424 serviceUrl: pyroutes.url('user_autocomplete_data'),
424 minChars:2,
425 minChars:2,
425 maxHeight:400,
426 maxHeight:400,
426 deferRequestBy: 300, //miliseconds
427 deferRequestBy: 300, //miliseconds
427 showNoSuggestionNotice: true,
428 showNoSuggestionNotice: true,
428 tabDisabled: true,
429 tabDisabled: true,
429 autoSelectFirst: true,
430 autoSelectFirst: true,
430 params: { user_id: templateContext.rhodecode_user.user_id, user_groups:true, user_groups_expand:true, skip_default_user:true },
431 params: { user_id: templateContext.rhodecode_user.user_id, user_groups:true, user_groups_expand:true, skip_default_user:true },
431 formatResult: autocompleteFormatResult,
432 formatResult: autocompleteFormatResult,
432 lookupFilter: autocompleteFilterResult,
433 lookupFilter: autocompleteFilterResult,
433 onSelect: function(element, data) {
434 onSelect: function(element, data) {
434 var mandatory = false;
435 var mandatory = false;
435 var reasons = [_gettext('added manually by "{0}"').format(templateContext.rhodecode_user.username)];
436 var reasons = [_gettext('added manually by "{0}"').format(templateContext.rhodecode_user.username)];
436
437
437 // add whole user groups
438 // add whole user groups
438 if (data.value_type == 'user_group') {
439 if (data.value_type == 'user_group') {
439 reasons.push(_gettext('member of "{0}"').format(data.value_display));
440 reasons.push(_gettext('member of "{0}"').format(data.value_display));
440
441
441 $.each(data.members, function(index, member_data) {
442 $.each(data.members, function(index, member_data) {
442 var reviewer = member_data;
443 var reviewer = member_data;
443 reviewer['user_id'] = member_data['id'];
444 reviewer['user_id'] = member_data['id'];
444 reviewer['gravatar_link'] = member_data['icon_link'];
445 reviewer['gravatar_link'] = member_data['icon_link'];
445 reviewer['user_link'] = member_data['profile_link'];
446 reviewer['user_link'] = member_data['profile_link'];
446 reviewer['rules'] = [];
447 reviewer['rules'] = [];
447 reviewersController.addReviewMember(reviewer, reasons, mandatory);
448 reviewersController.addReviewMember(reviewer, reasons, mandatory);
448 })
449 })
449 }
450 }
450 // add single user
451 // add single user
451 else {
452 else {
452 var reviewer = data;
453 var reviewer = data;
453 reviewer['user_id'] = data['id'];
454 reviewer['user_id'] = data['id'];
454 reviewer['gravatar_link'] = data['icon_link'];
455 reviewer['gravatar_link'] = data['icon_link'];
455 reviewer['user_link'] = data['profile_link'];
456 reviewer['user_link'] = data['profile_link'];
456 reviewer['rules'] = [];
457 reviewer['rules'] = [];
457 reviewersController.addReviewMember(reviewer, reasons, mandatory);
458 reviewersController.addReviewMember(reviewer, reasons, mandatory);
458 }
459 }
459
460
460 $(inputId).val('');
461 $(inputId).val('');
461 }
462 }
462 });
463 });
463 };
464 };
464
465
465
466
466 VersionController = function () {
467 VersionController = function () {
467 var self = this;
468 var self = this;
468 this.$verSource = $('input[name=ver_source]');
469 this.$verSource = $('input[name=ver_source]');
469 this.$verTarget = $('input[name=ver_target]');
470 this.$verTarget = $('input[name=ver_target]');
470 this.$showVersionDiff = $('#show-version-diff');
471 this.$showVersionDiff = $('#show-version-diff');
471
472
472 this.adjustRadioSelectors = function (curNode) {
473 this.adjustRadioSelectors = function (curNode) {
473 var getVal = function (item) {
474 var getVal = function (item) {
474 if (item == 'latest') {
475 if (item == 'latest') {
475 return Number.MAX_SAFE_INTEGER
476 return Number.MAX_SAFE_INTEGER
476 }
477 }
477 else {
478 else {
478 return parseInt(item)
479 return parseInt(item)
479 }
480 }
480 };
481 };
481
482
482 var curVal = getVal($(curNode).val());
483 var curVal = getVal($(curNode).val());
483 var cleared = false;
484 var cleared = false;
484
485
485 $.each(self.$verSource, function (index, value) {
486 $.each(self.$verSource, function (index, value) {
486 var elVal = getVal($(value).val());
487 var elVal = getVal($(value).val());
487
488
488 if (elVal > curVal) {
489 if (elVal > curVal) {
489 if ($(value).is(':checked')) {
490 if ($(value).is(':checked')) {
490 cleared = true;
491 cleared = true;
491 }
492 }
492 $(value).attr('disabled', 'disabled');
493 $(value).attr('disabled', 'disabled');
493 $(value).removeAttr('checked');
494 $(value).removeAttr('checked');
494 $(value).css({'opacity': 0.1});
495 $(value).css({'opacity': 0.1});
495 }
496 }
496 else {
497 else {
497 $(value).css({'opacity': 1});
498 $(value).css({'opacity': 1});
498 $(value).removeAttr('disabled');
499 $(value).removeAttr('disabled');
499 }
500 }
500 });
501 });
501
502
502 if (cleared) {
503 if (cleared) {
503 // if we unchecked an active, set the next one to same loc.
504 // if we unchecked an active, set the next one to same loc.
504 $(this.$verSource).filter('[value={0}]'.format(
505 $(this.$verSource).filter('[value={0}]'.format(
505 curVal)).attr('checked', 'checked');
506 curVal)).attr('checked', 'checked');
506 }
507 }
507
508
508 self.setLockAction(false,
509 self.setLockAction(false,
509 $(curNode).data('verPos'),
510 $(curNode).data('verPos'),
510 $(this.$verSource).filter(':checked').data('verPos')
511 $(this.$verSource).filter(':checked').data('verPos')
511 );
512 );
512 };
513 };
513
514
514
515
515 this.attachVersionListener = function () {
516 this.attachVersionListener = function () {
516 self.$verTarget.change(function (e) {
517 self.$verTarget.change(function (e) {
517 self.adjustRadioSelectors(this)
518 self.adjustRadioSelectors(this)
518 });
519 });
519 self.$verSource.change(function (e) {
520 self.$verSource.change(function (e) {
520 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
521 self.adjustRadioSelectors(self.$verTarget.filter(':checked'))
521 });
522 });
522 };
523 };
523
524
524 this.init = function () {
525 this.init = function () {
525
526
526 var curNode = self.$verTarget.filter(':checked');
527 var curNode = self.$verTarget.filter(':checked');
527 self.adjustRadioSelectors(curNode);
528 self.adjustRadioSelectors(curNode);
528 self.setLockAction(true);
529 self.setLockAction(true);
529 self.attachVersionListener();
530 self.attachVersionListener();
530
531
531 };
532 };
532
533
533 this.setLockAction = function (state, selectedVersion, otherVersion) {
534 this.setLockAction = function (state, selectedVersion, otherVersion) {
534 var $showVersionDiff = this.$showVersionDiff;
535 var $showVersionDiff = this.$showVersionDiff;
535
536
536 if (state) {
537 if (state) {
537 $showVersionDiff.attr('disabled', 'disabled');
538 $showVersionDiff.attr('disabled', 'disabled');
538 $showVersionDiff.addClass('disabled');
539 $showVersionDiff.addClass('disabled');
539 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
540 $showVersionDiff.html($showVersionDiff.data('labelTextLocked'));
540 }
541 }
541 else {
542 else {
542 $showVersionDiff.removeAttr('disabled');
543 $showVersionDiff.removeAttr('disabled');
543 $showVersionDiff.removeClass('disabled');
544 $showVersionDiff.removeClass('disabled');
544
545
545 if (selectedVersion == otherVersion) {
546 if (selectedVersion == otherVersion) {
546 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
547 $showVersionDiff.html($showVersionDiff.data('labelTextShow'));
547 } else {
548 } else {
548 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
549 $showVersionDiff.html($showVersionDiff.data('labelTextDiff'));
549 }
550 }
550 }
551 }
551
552
552 };
553 };
553
554
554 this.showVersionDiff = function () {
555 this.showVersionDiff = function () {
555 var target = self.$verTarget.filter(':checked');
556 var target = self.$verTarget.filter(':checked');
556 var source = self.$verSource.filter(':checked');
557 var source = self.$verSource.filter(':checked');
557
558
558 if (target.val() && source.val()) {
559 if (target.val() && source.val()) {
559 var params = {
560 var params = {
560 'pull_request_id': templateContext.pull_request_data.pull_request_id,
561 'pull_request_id': templateContext.pull_request_data.pull_request_id,
561 'repo_name': templateContext.repo_name,
562 'repo_name': templateContext.repo_name,
562 'version': target.val(),
563 'version': target.val(),
563 'from_version': source.val()
564 'from_version': source.val()
564 };
565 };
565 window.location = pyroutes.url('pullrequest_show', params)
566 window.location = pyroutes.url('pullrequest_show', params)
566 }
567 }
567
568
568 return false;
569 return false;
569 };
570 };
570
571
571 this.toggleVersionView = function (elem) {
572 this.toggleVersionView = function (elem) {
572
573
573 if (this.$showVersionDiff.is(':visible')) {
574 if (this.$showVersionDiff.is(':visible')) {
574 $('.version-pr').hide();
575 $('.version-pr').hide();
575 this.$showVersionDiff.hide();
576 this.$showVersionDiff.hide();
576 $(elem).html($(elem).data('toggleOn'))
577 $(elem).html($(elem).data('toggleOn'))
577 } else {
578 } else {
578 $('.version-pr').show();
579 $('.version-pr').show();
579 this.$showVersionDiff.show();
580 this.$showVersionDiff.show();
580 $(elem).html($(elem).data('toggleOff'))
581 $(elem).html($(elem).data('toggleOff'))
581 }
582 }
582
583
583 return false
584 return false
584 }
585 }
585
586
586 }; No newline at end of file
587 };
@@ -1,125 +1,129 b''
1 <%text>
1 <%text>
2 <div style="display: none">
2 <div style="display: none">
3
3
4 <script id="ejs_gravatarWithUser" type="text/template" class="ejsTemplate">
4 <script id="ejs_gravatarWithUser" type="text/template" class="ejsTemplate">
5
5
6 <%
6 <%
7 if (size > 16) {
7 if (size > 16) {
8 var gravatar_class = 'gravatar gravatar-large';
8 var gravatar_class = 'gravatar gravatar-large';
9 } else {
9 } else {
10 var gravatar_class = 'gravatar';
10 var gravatar_class = 'gravatar';
11 }
11 }
12 %>
12 %>
13
13
14 <%
14 <%
15 if (show_disabled) {
15 if (show_disabled) {
16 var user_cls = 'user user-disabled';
16 var user_cls = 'user user-disabled';
17 } else {
17 } else {
18 var user_cls = 'user';
18 var user_cls = 'user';
19 }
19 }
20 %>
20 %>
21
21
22 <div class="rc-user">
22 <div class="rc-user">
23 <img class="<%= gravatar_class %>" src="<%- gravatar_url -%>" height="<%= size %>" width="<%= size %>">
23 <img class="<%= gravatar_class %>" src="<%- gravatar_url -%>" height="<%= size %>" width="<%= size %>">
24 <span class="<%= user_cls %>"> <%- user_link -%> </span>
24 <span class="<%= user_cls %>"> <%- user_link -%> </span>
25 </div>
25 </div>
26
26
27 </script>
27 </script>
28
28
29 <script>
29 <script>
30 var CG = new ColorGenerator();
30 var CG = new ColorGenerator();
31 </script>
31 </script>
32
32
33 <script id="ejs_reviewMemberEntry" type="text/template" class="ejsTemplate">
33 <script id="ejs_reviewMemberEntry" type="text/template" class="ejsTemplate">
34
34
35 <li id="reviewer_<%= member.user_id %>" class="reviewer_entry">
35 <li id="reviewer_<%= member.user_id %>" class="reviewer_entry">
36 <%
36 <%
37 if (create) {
38 var edit_visibility = 'visible';
39 } else {
40 var edit_visibility = 'hidden';
41 }
37
42
38 if (member.user_group && member.user_group.vote_rule) {
43 if (member.user_group && member.user_group.vote_rule) {
39 var groupStyle = 'border-left: 1px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule));
44 var groupStyle = 'border-left: 1px solid '+CG.asRGB(CG.getColor(member.user_group.vote_rule));
40 } else {
45 } else {
41 var groupStyle = 'border-left: 1px solid white';
46 var groupStyle = 'border-left: 1px solid white';
42 }
47 }
43
44 %>
48 %>
45
49
46 <div class="reviewers_member" style="<%= groupStyle%>" >
50 <div class="reviewers_member" style="<%= groupStyle%>" >
47 <div class="reviewer_status tooltip" title="<%= review_status_label %>">
51 <div class="reviewer_status tooltip" title="<%= review_status_label %>">
48 <div class="flag_status <%= review_status %> pull-left reviewer_member_status"></div>
52 <div class="flag_status <%= review_status %> pull-left reviewer_member_status"></div>
49 </div>
53 </div>
50 <div id="reviewer_<%= member.user_id %>_name" class="reviewer_name">
54 <div id="reviewer_<%= member.user_id %>_name" class="reviewer_name">
51 <% if (mandatory) { %>
55 <% if (mandatory) { %>
52 <div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer">
56 <div class="reviewer_member_mandatory tooltip" title="Mandatory reviewer">
53 <i class="icon-lock"></i>
57 <i class="icon-lock"></i>
54 </div>
58 </div>
55 <% } %>
59 <% } %>
56
60
57 <%-
61 <%-
58 renderTemplate('gravatarWithUser', {
62 renderTemplate('gravatarWithUser', {
59 'size': 16,
63 'size': 16,
60 'show_disabled': false,
64 'show_disabled': false,
61 'user_link': member.user_link,
65 'user_link': member.user_link,
62 'gravatar_url': member.gravatar_link
66 'gravatar_url': member.gravatar_link
63 })
67 })
64 %>
68 %>
65 </div>
69 </div>
66
70
67 <input type="hidden" name="__start__" value="reviewer:mapping">
71 <input type="hidden" name="__start__" value="reviewer:mapping">
68
72
69
73
70 <%if (member.user_group && member.user_group.vote_rule) {%>
74 <%if (member.user_group && member.user_group.vote_rule) {%>
71 <div class="reviewer_reason">
75 <div class="reviewer_reason">
72
76
73 <%if (member.user_group.vote_rule == -1) {%>
77 <%if (member.user_group.vote_rule == -1) {%>
74 - group votes required: ALL
78 - group votes required: ALL
75 <%} else {%>
79 <%} else {%>
76 - group votes required: <%= member.user_group.vote_rule %>
80 - group votes required: <%= member.user_group.vote_rule %>
77 <%}%>
81 <%}%>
78 </div>
82 </div>
79 <%}%>
83 <%}%>
80
84
81 <input type="hidden" name="__start__" value="reasons:sequence">
85 <input type="hidden" name="__start__" value="reasons:sequence">
82 <% for (var i = 0; i < reasons.length; i++) { %>
86 <% for (var i = 0; i < reasons.length; i++) { %>
83 <% var reason = reasons[i] %>
87 <% var reason = reasons[i] %>
84 <div class="reviewer_reason">- <%= reason %></div>
88 <div class="reviewer_reason">- <%= reason %></div>
85 <input type="hidden" name="reason" value="<%= reason %>">
89 <input type="hidden" name="reason" value="<%= reason %>">
86 <% } %>
90 <% } %>
87 <input type="hidden" name="__end__" value="reasons:sequence">
91 <input type="hidden" name="__end__" value="reasons:sequence">
88
92
89 <input type="hidden" name="__start__" value="rules:sequence">
93 <input type="hidden" name="__start__" value="rules:sequence">
90 <% for (var i = 0; i < member.rules.length; i++) { %>
94 <% for (var i = 0; i < member.rules.length; i++) { %>
91 <% var rule = member.rules[i] %>
95 <% var rule = member.rules[i] %>
92 <input type="hidden" name="rule_id" value="<%= rule %>">
96 <input type="hidden" name="rule_id" value="<%= rule %>">
93 <% } %>
97 <% } %>
94 <input type="hidden" name="__end__" value="rules:sequence">
98 <input type="hidden" name="__end__" value="rules:sequence">
95
99
96 <input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" />
100 <input id="reviewer_<%= member.user_id %>_input" type="hidden" value="<%= member.user_id %>" name="user_id" />
97 <input type="hidden" name="mandatory" value="<%= mandatory %>"/>
101 <input type="hidden" name="mandatory" value="<%= mandatory %>"/>
98
102
99 <input type="hidden" name="__end__" value="reviewer:mapping">
103 <input type="hidden" name="__end__" value="reviewer:mapping">
100
104
101 <% if (mandatory) { %>
105 <% if (mandatory) { %>
102 <div class="reviewer_member_mandatory_remove" style="visibility: hidden;">
106 <div class="reviewer_member_mandatory_remove" style="visibility: <%= edit_visibility %>;">
103 <i class="icon-remove-sign"></i>
107 <i class="icon-remove-sign"></i>
104 </div>
108 </div>
105 <% } else { %>
109 <% } else { %>
106 <% if (allowed_to_update) { %>
110 <% if (allowed_to_update) { %>
107 <div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: hidden;">
111 <div class="reviewer_member_remove action_button" onclick="reviewersController.removeReviewMember(<%= member.user_id %>, true)" style="visibility: <%= edit_visibility %>;">
108 <i class="icon-remove-sign" ></i>
112 <i class="icon-remove-sign" ></i>
109 </div>
113 </div>
110 <% } %>
114 <% } %>
111 <% } %>
115 <% } %>
112 </div>
116 </div>
113 </li>
117 </li>
114
118
115 </script>
119 </script>
116
120
117
121
118 </div>
122 </div>
119
123
120 <script>
124 <script>
121 // registers the templates into global cache
125 // registers the templates into global cache
122 registerTemplates();
126 registerTemplates();
123 </script>
127 </script>
124
128
125 </%text>
129 </%text>
@@ -1,853 +1,854 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
5 ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <span id="pr-title">
12 <span id="pr-title">
13 ${c.pull_request.title}
13 ${c.pull_request.title}
14 %if c.pull_request.is_closed():
14 %if c.pull_request.is_closed():
15 (${_('Closed')})
15 (${_('Closed')})
16 %endif
16 %endif
17 </span>
17 </span>
18 <div id="pr-title-edit" class="input" style="display: none;">
18 <div id="pr-title-edit" class="input" style="display: none;">
19 ${h.text('pullrequest_title', id_="pr-title-input", class_="large", value=c.pull_request.title)}
19 ${h.text('pullrequest_title', id_="pr-title-input", class_="large", value=c.pull_request.title)}
20 </div>
20 </div>
21 </%def>
21 </%def>
22
22
23 <%def name="menu_bar_nav()">
23 <%def name="menu_bar_nav()">
24 ${self.menu_items(active='repositories')}
24 ${self.menu_items(active='repositories')}
25 </%def>
25 </%def>
26
26
27 <%def name="menu_bar_subnav()">
27 <%def name="menu_bar_subnav()">
28 ${self.repo_menu(active='showpullrequest')}
28 ${self.repo_menu(active='showpullrequest')}
29 </%def>
29 </%def>
30
30
31 <%def name="main()">
31 <%def name="main()">
32
32
33 <script type="text/javascript">
33 <script type="text/javascript">
34 // TODO: marcink switch this to pyroutes
34 // TODO: marcink switch this to pyroutes
35 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
35 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
36 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
36 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
37 </script>
37 </script>
38 <div class="box">
38 <div class="box">
39
39
40 <div class="title">
40 <div class="title">
41 ${self.repo_page_title(c.rhodecode_db_repo)}
41 ${self.repo_page_title(c.rhodecode_db_repo)}
42 </div>
42 </div>
43
43
44 ${self.breadcrumbs()}
44 ${self.breadcrumbs()}
45
45
46 <div class="box pr-summary">
46 <div class="box pr-summary">
47
47
48 <div class="summary-details block-left">
48 <div class="summary-details block-left">
49 <% summary = lambda n:{False:'summary-short'}.get(n) %>
49 <% summary = lambda n:{False:'summary-short'}.get(n) %>
50 <div class="pr-details-title">
50 <div class="pr-details-title">
51 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request #%s') % c.pull_request.pull_request_id}</a> ${_('From')} ${h.format_date(c.pull_request.created_on)}
51 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request #%s') % c.pull_request.pull_request_id}</a> ${_('From')} ${h.format_date(c.pull_request.created_on)}
52 %if c.allowed_to_update:
52 %if c.allowed_to_update:
53 <div id="delete_pullrequest" class="pull-right action_button ${'' if c.allowed_to_delete else 'disabled' }" style="clear:inherit;padding: 0">
53 <div id="delete_pullrequest" class="pull-right action_button ${'' if c.allowed_to_delete else 'disabled' }" style="clear:inherit;padding: 0">
54 % if c.allowed_to_delete:
54 % if c.allowed_to_delete:
55 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
55 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
56 ${h.submit('remove_%s' % c.pull_request.pull_request_id, _('Delete'),
56 ${h.submit('remove_%s' % c.pull_request.pull_request_id, _('Delete'),
57 class_="btn btn-link btn-danger no-margin",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
57 class_="btn btn-link btn-danger no-margin",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
58 ${h.end_form()}
58 ${h.end_form()}
59 % else:
59 % else:
60 ${_('Delete')}
60 ${_('Delete')}
61 % endif
61 % endif
62 </div>
62 </div>
63 <div id="open_edit_pullrequest" class="pull-right action_button">${_('Edit')}</div>
63 <div id="open_edit_pullrequest" class="pull-right action_button">${_('Edit')}</div>
64 <div id="close_edit_pullrequest" class="pull-right action_button" style="display: none;padding: 0">${_('Cancel')}</div>
64 <div id="close_edit_pullrequest" class="pull-right action_button" style="display: none;padding: 0">${_('Cancel')}</div>
65 %endif
65 %endif
66 </div>
66 </div>
67
67
68 <div id="summary" class="fields pr-details-content">
68 <div id="summary" class="fields pr-details-content">
69 <div class="field">
69 <div class="field">
70 <div class="label-summary">
70 <div class="label-summary">
71 <label>${_('Source')}:</label>
71 <label>${_('Source')}:</label>
72 </div>
72 </div>
73 <div class="input">
73 <div class="input">
74 <div class="pr-origininfo">
74 <div class="pr-origininfo">
75 ## branch link is only valid if it is a branch
75 ## branch link is only valid if it is a branch
76 <span class="tag">
76 <span class="tag">
77 %if c.pull_request.source_ref_parts.type == 'branch':
77 %if c.pull_request.source_ref_parts.type == 'branch':
78 <a href="${h.route_path('repo_changelog', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}">${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}</a>
78 <a href="${h.route_path('repo_changelog', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}">${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}</a>
79 %else:
79 %else:
80 ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}
80 ${c.pull_request.source_ref_parts.type}: ${c.pull_request.source_ref_parts.name}
81 %endif
81 %endif
82 </span>
82 </span>
83 <span class="clone-url">
83 <span class="clone-url">
84 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
84 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
85 </span>
85 </span>
86 <br/>
86 <br/>
87 % if c.ancestor_commit:
87 % if c.ancestor_commit:
88 ${_('Common ancestor')}:
88 ${_('Common ancestor')}:
89 <code><a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a></code>
89 <code><a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a></code>
90 % endif
90 % endif
91 </div>
91 </div>
92 %if h.is_hg(c.pull_request.source_repo):
92 %if h.is_hg(c.pull_request.source_repo):
93 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
93 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
94 %elif h.is_git(c.pull_request.source_repo):
94 %elif h.is_git(c.pull_request.source_repo):
95 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
95 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
96 %endif
96 %endif
97
97
98 <div class="">
98 <div class="">
99 <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
99 <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
100 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
100 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
101 </div>
101 </div>
102
102
103 </div>
103 </div>
104 </div>
104 </div>
105 <div class="field">
105 <div class="field">
106 <div class="label-summary">
106 <div class="label-summary">
107 <label>${_('Target')}:</label>
107 <label>${_('Target')}:</label>
108 </div>
108 </div>
109 <div class="input">
109 <div class="input">
110 <div class="pr-targetinfo">
110 <div class="pr-targetinfo">
111 ## branch link is only valid if it is a branch
111 ## branch link is only valid if it is a branch
112 <span class="tag">
112 <span class="tag">
113 %if c.pull_request.target_ref_parts.type == 'branch':
113 %if c.pull_request.target_ref_parts.type == 'branch':
114 <a href="${h.route_path('repo_changelog', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}">${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}</a>
114 <a href="${h.route_path('repo_changelog', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}">${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}</a>
115 %else:
115 %else:
116 ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}
116 ${c.pull_request.target_ref_parts.type}: ${c.pull_request.target_ref_parts.name}
117 %endif
117 %endif
118 </span>
118 </span>
119 <span class="clone-url">
119 <span class="clone-url">
120 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
120 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
121 </span>
121 </span>
122 </div>
122 </div>
123 </div>
123 </div>
124 </div>
124 </div>
125
125
126 ## Link to the shadow repository.
126 ## Link to the shadow repository.
127 <div class="field">
127 <div class="field">
128 <div class="label-summary">
128 <div class="label-summary">
129 <label>${_('Merge')}:</label>
129 <label>${_('Merge')}:</label>
130 </div>
130 </div>
131 <div class="input">
131 <div class="input">
132 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
132 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
133 %if h.is_hg(c.pull_request.target_repo):
133 %if h.is_hg(c.pull_request.target_repo):
134 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
134 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
135 %elif h.is_git(c.pull_request.target_repo):
135 %elif h.is_git(c.pull_request.target_repo):
136 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
136 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
137 %endif
137 %endif
138 <div class="">
138 <div class="">
139 <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
139 <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
140 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
140 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
141 </div>
141 </div>
142 % else:
142 % else:
143 <div class="">
143 <div class="">
144 ${_('Shadow repository data not available')}.
144 ${_('Shadow repository data not available')}.
145 </div>
145 </div>
146 % endif
146 % endif
147 </div>
147 </div>
148 </div>
148 </div>
149
149
150 <div class="field">
150 <div class="field">
151 <div class="label-summary">
151 <div class="label-summary">
152 <label>${_('Review')}:</label>
152 <label>${_('Review')}:</label>
153 </div>
153 </div>
154 <div class="input">
154 <div class="input">
155 %if c.pull_request_review_status:
155 %if c.pull_request_review_status:
156 <div class="${'flag_status %s' % c.pull_request_review_status} tooltip pull-left"></div>
156 <div class="${'flag_status %s' % c.pull_request_review_status} tooltip pull-left"></div>
157 <span class="changeset-status-lbl tooltip">
157 <span class="changeset-status-lbl tooltip">
158 %if c.pull_request.is_closed():
158 %if c.pull_request.is_closed():
159 ${_('Closed')},
159 ${_('Closed')},
160 %endif
160 %endif
161 ${h.commit_status_lbl(c.pull_request_review_status)}
161 ${h.commit_status_lbl(c.pull_request_review_status)}
162 </span>
162 </span>
163 - ${_ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)}
163 - ${_ungettext('calculated based on %s reviewer vote', 'calculated based on %s reviewers votes', len(c.pull_request_reviewers)) % len(c.pull_request_reviewers)}
164 %endif
164 %endif
165 </div>
165 </div>
166 </div>
166 </div>
167 <div class="field">
167 <div class="field">
168 <div class="pr-description-label label-summary">
168 <div class="pr-description-label label-summary">
169 <label>${_('Description')}:</label>
169 <label>${_('Description')}:</label>
170 </div>
170 </div>
171 <div id="pr-desc" class="input">
171 <div id="pr-desc" class="input">
172 <div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
172 <div class="pr-description">${h.urlify_commit_message(c.pull_request.description, c.repo_name)}</div>
173 </div>
173 </div>
174 <div id="pr-desc-edit" class="input textarea editor" style="display: none;">
174 <div id="pr-desc-edit" class="input textarea editor" style="display: none;">
175 <textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
175 <textarea id="pr-description-input" size="30">${c.pull_request.description}</textarea>
176 </div>
176 </div>
177 </div>
177 </div>
178
178
179 <div class="field">
179 <div class="field">
180 <div class="label-summary">
180 <div class="label-summary">
181 <label>${_('Versions')}:</label>
181 <label>${_('Versions')}:</label>
182 </div>
182 </div>
183
183
184 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
184 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
185 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
185 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
186
186
187 <div class="pr-versions">
187 <div class="pr-versions">
188 % if c.show_version_changes:
188 % if c.show_version_changes:
189 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
189 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
190 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
190 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
191 <a id="show-pr-versions" class="input" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
191 <a id="show-pr-versions" class="input" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
192 data-toggle-on="${_ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))}"
192 data-toggle-on="${_ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))}"
193 data-toggle-off="${_('Hide all versions of this pull request')}">
193 data-toggle-off="${_('Hide all versions of this pull request')}">
194 ${_ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))}
194 ${_ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))}
195 </a>
195 </a>
196 <table>
196 <table>
197 ## SHOW ALL VERSIONS OF PR
197 ## SHOW ALL VERSIONS OF PR
198 <% ver_pr = None %>
198 <% ver_pr = None %>
199
199
200 % for data in reversed(list(enumerate(c.versions, 1))):
200 % for data in reversed(list(enumerate(c.versions, 1))):
201 <% ver_pos = data[0] %>
201 <% ver_pos = data[0] %>
202 <% ver = data[1] %>
202 <% ver = data[1] %>
203 <% ver_pr = ver.pull_request_version_id %>
203 <% ver_pr = ver.pull_request_version_id %>
204 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
204 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
205
205
206 <tr class="version-pr" style="display: ${display_row}">
206 <tr class="version-pr" style="display: ${display_row}">
207 <td>
207 <td>
208 <code>
208 <code>
209 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
209 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
210 </code>
210 </code>
211 </td>
211 </td>
212 <td>
212 <td>
213 <input ${'checked="checked"' if c.from_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
213 <input ${'checked="checked"' if c.from_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
214 <input ${'checked="checked"' if c.at_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
214 <input ${'checked="checked"' if c.at_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
215 </td>
215 </td>
216 <td>
216 <td>
217 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
217 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
218 <div class="${'flag_status %s' % review_status} tooltip pull-left" title="${_('Your review status at this version')}">
218 <div class="${'flag_status %s' % review_status} tooltip pull-left" title="${_('Your review status at this version')}">
219 </div>
219 </div>
220 </td>
220 </td>
221 <td>
221 <td>
222 % if c.at_version_num != ver_pr:
222 % if c.at_version_num != ver_pr:
223 <i class="icon-comment"></i>
223 <i class="icon-comment"></i>
224 <code class="tooltip" title="${_('Comment from pull request version {0}, general:{1} inline:{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}">
224 <code class="tooltip" title="${_('Comment from pull request version {0}, general:{1} inline:{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}">
225 G:${len(c.comment_versions[ver_pr]['at'])} / I:${len(c.inline_versions[ver_pr]['at'])}
225 G:${len(c.comment_versions[ver_pr]['at'])} / I:${len(c.inline_versions[ver_pr]['at'])}
226 </code>
226 </code>
227 % endif
227 % endif
228 </td>
228 </td>
229 <td>
229 <td>
230 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
230 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
231 </td>
231 </td>
232 <td>
232 <td>
233 ${h.age_component(ver.updated_on, time_is_local=True)}
233 ${h.age_component(ver.updated_on, time_is_local=True)}
234 </td>
234 </td>
235 </tr>
235 </tr>
236 % endfor
236 % endfor
237
237
238 <tr>
238 <tr>
239 <td colspan="6">
239 <td colspan="6">
240 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
240 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
241 data-label-text-locked="${_('select versions to show changes')}"
241 data-label-text-locked="${_('select versions to show changes')}"
242 data-label-text-diff="${_('show changes between versions')}"
242 data-label-text-diff="${_('show changes between versions')}"
243 data-label-text-show="${_('show pull request for this version')}"
243 data-label-text-show="${_('show pull request for this version')}"
244 >
244 >
245 ${_('select versions to show changes')}
245 ${_('select versions to show changes')}
246 </button>
246 </button>
247 </td>
247 </td>
248 </tr>
248 </tr>
249
249
250 ## show comment/inline comments summary
250 ## show comment/inline comments summary
251 <%def name="comments_summary()">
251 <%def name="comments_summary()">
252 <tr>
252 <tr>
253 <td colspan="6" class="comments-summary-td">
253 <td colspan="6" class="comments-summary-td">
254
254
255 % if c.at_version:
255 % if c.at_version:
256 <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['display']) %>
256 <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['display']) %>
257 <% general_comm_count_ver = len(c.comment_versions[c.at_version_num]['display']) %>
257 <% general_comm_count_ver = len(c.comment_versions[c.at_version_num]['display']) %>
258 ${_('Comments at this version')}:
258 ${_('Comments at this version')}:
259 % else:
259 % else:
260 <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['until']) %>
260 <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['until']) %>
261 <% general_comm_count_ver = len(c.comment_versions[c.at_version_num]['until']) %>
261 <% general_comm_count_ver = len(c.comment_versions[c.at_version_num]['until']) %>
262 ${_('Comments for this pull request')}:
262 ${_('Comments for this pull request')}:
263 % endif
263 % endif
264
264
265
265
266 %if general_comm_count_ver:
266 %if general_comm_count_ver:
267 <a href="#comments">${_("%d General ") % general_comm_count_ver}</a>
267 <a href="#comments">${_("%d General ") % general_comm_count_ver}</a>
268 %else:
268 %else:
269 ${_("%d General ") % general_comm_count_ver}
269 ${_("%d General ") % general_comm_count_ver}
270 %endif
270 %endif
271
271
272 %if inline_comm_count_ver:
272 %if inline_comm_count_ver:
273 , <a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${_("%d Inline") % inline_comm_count_ver}</a>
273 , <a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${_("%d Inline") % inline_comm_count_ver}</a>
274 %else:
274 %else:
275 , ${_("%d Inline") % inline_comm_count_ver}
275 , ${_("%d Inline") % inline_comm_count_ver}
276 %endif
276 %endif
277
277
278 %if outdated_comm_count_ver:
278 %if outdated_comm_count_ver:
279 , <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">${_("%d Outdated") % outdated_comm_count_ver}</a>
279 , <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">${_("%d Outdated") % outdated_comm_count_ver}</a>
280 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated comments')}</a>
280 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated comments')}</a>
281 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated comments')}</a>
281 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated comments')}</a>
282 %else:
282 %else:
283 , ${_("%d Outdated") % outdated_comm_count_ver}
283 , ${_("%d Outdated") % outdated_comm_count_ver}
284 %endif
284 %endif
285 </td>
285 </td>
286 </tr>
286 </tr>
287 </%def>
287 </%def>
288 ${comments_summary()}
288 ${comments_summary()}
289 </table>
289 </table>
290 % else:
290 % else:
291 <div class="input">
291 <div class="input">
292 ${_('Pull request versions not available')}.
292 ${_('Pull request versions not available')}.
293 </div>
293 </div>
294 <div>
294 <div>
295 <table>
295 <table>
296 ${comments_summary()}
296 ${comments_summary()}
297 </table>
297 </table>
298 </div>
298 </div>
299 % endif
299 % endif
300 </div>
300 </div>
301 </div>
301 </div>
302
302
303 <div id="pr-save" class="field" style="display: none;">
303 <div id="pr-save" class="field" style="display: none;">
304 <div class="label-summary"></div>
304 <div class="label-summary"></div>
305 <div class="input">
305 <div class="input">
306 <span id="edit_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</span>
306 <span id="edit_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</span>
307 </div>
307 </div>
308 </div>
308 </div>
309 </div>
309 </div>
310 </div>
310 </div>
311 <div>
311 <div>
312 ## AUTHOR
312 ## AUTHOR
313 <div class="reviewers-title block-right">
313 <div class="reviewers-title block-right">
314 <div class="pr-details-title">
314 <div class="pr-details-title">
315 ${_('Author of this pull request')}
315 ${_('Author of this pull request')}
316 </div>
316 </div>
317 </div>
317 </div>
318 <div class="block-right pr-details-content reviewers">
318 <div class="block-right pr-details-content reviewers">
319 <ul class="group_members">
319 <ul class="group_members">
320 <li>
320 <li>
321 ${self.gravatar_with_user(c.pull_request.author.email, 16)}
321 ${self.gravatar_with_user(c.pull_request.author.email, 16)}
322 </li>
322 </li>
323 </ul>
323 </ul>
324 </div>
324 </div>
325
325
326 ## REVIEW RULES
326 ## REVIEW RULES
327 <div id="review_rules" style="display: none" class="reviewers-title block-right">
327 <div id="review_rules" style="display: none" class="reviewers-title block-right">
328 <div class="pr-details-title">
328 <div class="pr-details-title">
329 ${_('Reviewer rules')}
329 ${_('Reviewer rules')}
330 %if c.allowed_to_update:
330 %if c.allowed_to_update:
331 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
331 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
332 %endif
332 %endif
333 </div>
333 </div>
334 <div class="pr-reviewer-rules">
334 <div class="pr-reviewer-rules">
335 ## review rules will be appended here, by default reviewers logic
335 ## review rules will be appended here, by default reviewers logic
336 </div>
336 </div>
337 <input id="review_data" type="hidden" name="review_data" value="">
337 <input id="review_data" type="hidden" name="review_data" value="">
338 </div>
338 </div>
339
339
340 ## REVIEWERS
340 ## REVIEWERS
341 <div class="reviewers-title block-right">
341 <div class="reviewers-title block-right">
342 <div class="pr-details-title">
342 <div class="pr-details-title">
343 ${_('Pull request reviewers')}
343 ${_('Pull request reviewers')}
344 %if c.allowed_to_update:
344 %if c.allowed_to_update:
345 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
345 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
346 %endif
346 %endif
347 </div>
347 </div>
348 </div>
348 </div>
349 <div id="reviewers" class="block-right pr-details-content reviewers">
349 <div id="reviewers" class="block-right pr-details-content reviewers">
350
350
351 ## members redering block
351 ## members redering block
352 <input type="hidden" name="__start__" value="review_members:sequence">
352 <input type="hidden" name="__start__" value="review_members:sequence">
353 <ul id="review_members" class="group_members">
353 <ul id="review_members" class="group_members">
354
354
355 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
355 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
356 <script>
356 <script>
357 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
357 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
358 var status = "${(status[0][1].status if status else 'not_reviewed')}";
358 var status = "${(status[0][1].status if status else 'not_reviewed')}";
359 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
359 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
360 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
360 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
361
361
362 var entry = renderTemplate('reviewMemberEntry', {
362 var entry = renderTemplate('reviewMemberEntry', {
363 'member': member,
363 'member': member,
364 'mandatory': member.mandatory,
364 'mandatory': member.mandatory,
365 'reasons': member.reasons,
365 'reasons': member.reasons,
366 'allowed_to_update': allowed_to_update,
366 'allowed_to_update': allowed_to_update,
367 'review_status': status,
367 'review_status': status,
368 'review_status_label': status_lbl,
368 'review_status_label': status_lbl,
369 'user_group': member.user_group
369 'user_group': member.user_group,
370 'create': false
370 });
371 });
371 $('#review_members').append(entry)
372 $('#review_members').append(entry)
372 </script>
373 </script>
373
374
374 % endfor
375 % endfor
375
376
376 </ul>
377 </ul>
377 <input type="hidden" name="__end__" value="review_members:sequence">
378 <input type="hidden" name="__end__" value="review_members:sequence">
378 ## end members redering block
379 ## end members redering block
379
380
380 %if not c.pull_request.is_closed():
381 %if not c.pull_request.is_closed():
381 <div id="add_reviewer" class="ac" style="display: none;">
382 <div id="add_reviewer" class="ac" style="display: none;">
382 %if c.allowed_to_update:
383 %if c.allowed_to_update:
383 % if not c.forbid_adding_reviewers:
384 % if not c.forbid_adding_reviewers:
384 <div id="add_reviewer_input" class="reviewer_ac">
385 <div id="add_reviewer_input" class="reviewer_ac">
385 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
386 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
386 <div id="reviewers_container"></div>
387 <div id="reviewers_container"></div>
387 </div>
388 </div>
388 % endif
389 % endif
389 <div class="pull-right">
390 <div class="pull-right">
390 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
391 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
391 </div>
392 </div>
392 %endif
393 %endif
393 </div>
394 </div>
394 %endif
395 %endif
395 </div>
396 </div>
396 </div>
397 </div>
397 </div>
398 </div>
398 <div class="box">
399 <div class="box">
399 ##DIFF
400 ##DIFF
400 <div class="table" >
401 <div class="table" >
401 <div id="changeset_compare_view_content">
402 <div id="changeset_compare_view_content">
402 ##CS
403 ##CS
403 % if c.missing_requirements:
404 % if c.missing_requirements:
404 <div class="box">
405 <div class="box">
405 <div class="alert alert-warning">
406 <div class="alert alert-warning">
406 <div>
407 <div>
407 <strong>${_('Missing requirements:')}</strong>
408 <strong>${_('Missing requirements:')}</strong>
408 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
409 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
409 </div>
410 </div>
410 </div>
411 </div>
411 </div>
412 </div>
412 % elif c.missing_commits:
413 % elif c.missing_commits:
413 <div class="box">
414 <div class="box">
414 <div class="alert alert-warning">
415 <div class="alert alert-warning">
415 <div>
416 <div>
416 <strong>${_('Missing commits')}:</strong>
417 <strong>${_('Missing commits')}:</strong>
417 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
418 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
418 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
419 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
419 </div>
420 </div>
420 </div>
421 </div>
421 </div>
422 </div>
422 % endif
423 % endif
423
424
424 <div class="compare_view_commits_title">
425 <div class="compare_view_commits_title">
425 % if not c.compare_mode:
426 % if not c.compare_mode:
426
427
427 % if c.at_version_pos:
428 % if c.at_version_pos:
428 <h4>
429 <h4>
429 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
430 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
430 </h4>
431 </h4>
431 % endif
432 % endif
432
433
433 <div class="pull-left">
434 <div class="pull-left">
434 <div class="btn-group">
435 <div class="btn-group">
435 <a
436 <a
436 class="btn"
437 class="btn"
437 href="#"
438 href="#"
438 onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false">
439 onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false">
439 ${_ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
440 ${_ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
440 </a>
441 </a>
441 <a
442 <a
442 class="btn"
443 class="btn"
443 href="#"
444 href="#"
444 onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false">
445 onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false">
445 ${_ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
446 ${_ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
446 </a>
447 </a>
447 </div>
448 </div>
448 </div>
449 </div>
449
450
450 <div class="pull-right">
451 <div class="pull-right">
451 % if c.allowed_to_update and not c.pull_request.is_closed():
452 % if c.allowed_to_update and not c.pull_request.is_closed():
452 <a id="update_commits" class="btn btn-primary no-margin pull-right">${_('Update commits')}</a>
453 <a id="update_commits" class="btn btn-primary no-margin pull-right">${_('Update commits')}</a>
453 % else:
454 % else:
454 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
455 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
455 % endif
456 % endif
456
457
457 </div>
458 </div>
458 % endif
459 % endif
459 </div>
460 </div>
460
461
461 % if not c.missing_commits:
462 % if not c.missing_commits:
462 % if c.compare_mode:
463 % if c.compare_mode:
463 % if c.at_version:
464 % if c.at_version:
464 <h4>
465 <h4>
465 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
466 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
466 </h4>
467 </h4>
467
468
468 <div class="subtitle-compare">
469 <div class="subtitle-compare">
469 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
470 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
470 </div>
471 </div>
471
472
472 <div class="container">
473 <div class="container">
473 <table class="rctable compare_view_commits">
474 <table class="rctable compare_view_commits">
474 <tr>
475 <tr>
475 <th></th>
476 <th></th>
476 <th>${_('Time')}</th>
477 <th>${_('Time')}</th>
477 <th>${_('Author')}</th>
478 <th>${_('Author')}</th>
478 <th>${_('Commit')}</th>
479 <th>${_('Commit')}</th>
479 <th></th>
480 <th></th>
480 <th>${_('Description')}</th>
481 <th>${_('Description')}</th>
481 </tr>
482 </tr>
482
483
483 % for c_type, commit in c.commit_changes:
484 % for c_type, commit in c.commit_changes:
484 % if c_type in ['a', 'r']:
485 % if c_type in ['a', 'r']:
485 <%
486 <%
486 if c_type == 'a':
487 if c_type == 'a':
487 cc_title = _('Commit added in displayed changes')
488 cc_title = _('Commit added in displayed changes')
488 elif c_type == 'r':
489 elif c_type == 'r':
489 cc_title = _('Commit removed in displayed changes')
490 cc_title = _('Commit removed in displayed changes')
490 else:
491 else:
491 cc_title = ''
492 cc_title = ''
492 %>
493 %>
493 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
494 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
494 <td>
495 <td>
495 <div class="commit-change-indicator color-${c_type}-border">
496 <div class="commit-change-indicator color-${c_type}-border">
496 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
497 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
497 ${c_type.upper()}
498 ${c_type.upper()}
498 </div>
499 </div>
499 </div>
500 </div>
500 </td>
501 </td>
501 <td class="td-time">
502 <td class="td-time">
502 ${h.age_component(commit.date)}
503 ${h.age_component(commit.date)}
503 </td>
504 </td>
504 <td class="td-user">
505 <td class="td-user">
505 ${base.gravatar_with_user(commit.author, 16)}
506 ${base.gravatar_with_user(commit.author, 16)}
506 </td>
507 </td>
507 <td class="td-hash">
508 <td class="td-hash">
508 <code>
509 <code>
509 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
510 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
510 r${commit.revision}:${h.short_id(commit.raw_id)}
511 r${commit.revision}:${h.short_id(commit.raw_id)}
511 </a>
512 </a>
512 ${h.hidden('revisions', commit.raw_id)}
513 ${h.hidden('revisions', commit.raw_id)}
513 </code>
514 </code>
514 </td>
515 </td>
515 <td class="expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}">
516 <td class="expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}">
516 <div class="show_more_col">
517 <div class="show_more_col">
517 <i class="show_more"></i>
518 <i class="show_more"></i>
518 </div>
519 </div>
519 </td>
520 </td>
520 <td class="mid td-description">
521 <td class="mid td-description">
521 <div class="log-container truncate-wrap">
522 <div class="log-container truncate-wrap">
522 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">
523 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">
523 ${h.urlify_commit_message(commit.message, c.repo_name)}
524 ${h.urlify_commit_message(commit.message, c.repo_name)}
524 </div>
525 </div>
525 </div>
526 </div>
526 </td>
527 </td>
527 </tr>
528 </tr>
528 % endif
529 % endif
529 % endfor
530 % endfor
530 </table>
531 </table>
531 </div>
532 </div>
532
533
533 <script>
534 <script>
534 $('.expand_commit').on('click',function(e){
535 $('.expand_commit').on('click',function(e){
535 var target_expand = $(this);
536 var target_expand = $(this);
536 var cid = target_expand.data('commitId');
537 var cid = target_expand.data('commitId');
537
538
538 if (target_expand.hasClass('open')){
539 if (target_expand.hasClass('open')){
539 $('#c-'+cid).css({
540 $('#c-'+cid).css({
540 'height': '1.5em',
541 'height': '1.5em',
541 'white-space': 'nowrap',
542 'white-space': 'nowrap',
542 'text-overflow': 'ellipsis',
543 'text-overflow': 'ellipsis',
543 'overflow':'hidden'
544 'overflow':'hidden'
544 });
545 });
545 target_expand.removeClass('open');
546 target_expand.removeClass('open');
546 }
547 }
547 else {
548 else {
548 $('#c-'+cid).css({
549 $('#c-'+cid).css({
549 'height': 'auto',
550 'height': 'auto',
550 'white-space': 'pre-line',
551 'white-space': 'pre-line',
551 'text-overflow': 'initial',
552 'text-overflow': 'initial',
552 'overflow':'visible'
553 'overflow':'visible'
553 });
554 });
554 target_expand.addClass('open');
555 target_expand.addClass('open');
555 }
556 }
556 });
557 });
557 </script>
558 </script>
558
559
559 % endif
560 % endif
560
561
561 % else:
562 % else:
562 <%include file="/compare/compare_commits.mako" />
563 <%include file="/compare/compare_commits.mako" />
563 % endif
564 % endif
564
565
565 <div class="cs_files">
566 <div class="cs_files">
566 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
567 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
567 ${cbdiffs.render_diffset_menu()}
568 ${cbdiffs.render_diffset_menu()}
568 ${cbdiffs.render_diffset(
569 ${cbdiffs.render_diffset(
569 c.diffset, use_comments=True,
570 c.diffset, use_comments=True,
570 collapse_when_files_over=30,
571 collapse_when_files_over=30,
571 disable_new_comments=not c.allowed_to_comment,
572 disable_new_comments=not c.allowed_to_comment,
572 deleted_files_comments=c.deleted_files_comments)}
573 deleted_files_comments=c.deleted_files_comments)}
573 </div>
574 </div>
574 % else:
575 % else:
575 ## skipping commits we need to clear the view for missing commits
576 ## skipping commits we need to clear the view for missing commits
576 <div style="clear:both;"></div>
577 <div style="clear:both;"></div>
577 % endif
578 % endif
578
579
579 </div>
580 </div>
580 </div>
581 </div>
581
582
582 ## template for inline comment form
583 ## template for inline comment form
583 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
584 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
584
585
585 ## render general comments
586 ## render general comments
586
587
587 <div id="comment-tr-show">
588 <div id="comment-tr-show">
588 <div class="comment">
589 <div class="comment">
589 % if general_outdated_comm_count_ver:
590 % if general_outdated_comm_count_ver:
590 <div class="meta">
591 <div class="meta">
591 % if general_outdated_comm_count_ver == 1:
592 % if general_outdated_comm_count_ver == 1:
592 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
593 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
593 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
594 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
594 % else:
595 % else:
595 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
596 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
596 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
597 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
597 % endif
598 % endif
598 </div>
599 </div>
599 % endif
600 % endif
600 </div>
601 </div>
601 </div>
602 </div>
602
603
603 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
604 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
604
605
605 % if not c.pull_request.is_closed():
606 % if not c.pull_request.is_closed():
606 ## merge status, and merge action
607 ## merge status, and merge action
607 <div class="pull-request-merge">
608 <div class="pull-request-merge">
608 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
609 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
609 </div>
610 </div>
610
611
611 ## main comment form and it status
612 ## main comment form and it status
612 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
613 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
613 pull_request_id=c.pull_request.pull_request_id),
614 pull_request_id=c.pull_request.pull_request_id),
614 c.pull_request_review_status,
615 c.pull_request_review_status,
615 is_pull_request=True, change_status=c.allowed_to_change_status)}
616 is_pull_request=True, change_status=c.allowed_to_change_status)}
616 %endif
617 %endif
617
618
618 <script type="text/javascript">
619 <script type="text/javascript">
619 if (location.hash) {
620 if (location.hash) {
620 var result = splitDelimitedHash(location.hash);
621 var result = splitDelimitedHash(location.hash);
621 var line = $('html').find(result.loc);
622 var line = $('html').find(result.loc);
622 // show hidden comments if we use location.hash
623 // show hidden comments if we use location.hash
623 if (line.hasClass('comment-general')) {
624 if (line.hasClass('comment-general')) {
624 $(line).show();
625 $(line).show();
625 } else if (line.hasClass('comment-inline')) {
626 } else if (line.hasClass('comment-inline')) {
626 $(line).show();
627 $(line).show();
627 var $cb = $(line).closest('.cb');
628 var $cb = $(line).closest('.cb');
628 $cb.removeClass('cb-collapsed')
629 $cb.removeClass('cb-collapsed')
629 }
630 }
630 if (line.length > 0){
631 if (line.length > 0){
631 offsetScroll(line, 70);
632 offsetScroll(line, 70);
632 }
633 }
633 }
634 }
634
635
635 versionController = new VersionController();
636 versionController = new VersionController();
636 versionController.init();
637 versionController.init();
637
638
638 reviewersController = new ReviewersController();
639 reviewersController = new ReviewersController();
639
640
640 $(function(){
641 $(function(){
641
642
642 // custom code mirror
643 // custom code mirror
643 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
644 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
644
645
645 var PRDetails = {
646 var PRDetails = {
646 editButton: $('#open_edit_pullrequest'),
647 editButton: $('#open_edit_pullrequest'),
647 closeButton: $('#close_edit_pullrequest'),
648 closeButton: $('#close_edit_pullrequest'),
648 deleteButton: $('#delete_pullrequest'),
649 deleteButton: $('#delete_pullrequest'),
649 viewFields: $('#pr-desc, #pr-title'),
650 viewFields: $('#pr-desc, #pr-title'),
650 editFields: $('#pr-desc-edit, #pr-title-edit, #pr-save'),
651 editFields: $('#pr-desc-edit, #pr-title-edit, #pr-save'),
651
652
652 init: function() {
653 init: function() {
653 var that = this;
654 var that = this;
654 this.editButton.on('click', function(e) { that.edit(); });
655 this.editButton.on('click', function(e) { that.edit(); });
655 this.closeButton.on('click', function(e) { that.view(); });
656 this.closeButton.on('click', function(e) { that.view(); });
656 },
657 },
657
658
658 edit: function(event) {
659 edit: function(event) {
659 this.viewFields.hide();
660 this.viewFields.hide();
660 this.editButton.hide();
661 this.editButton.hide();
661 this.deleteButton.hide();
662 this.deleteButton.hide();
662 this.closeButton.show();
663 this.closeButton.show();
663 this.editFields.show();
664 this.editFields.show();
664 codeMirrorInstance.refresh();
665 codeMirrorInstance.refresh();
665 },
666 },
666
667
667 view: function(event) {
668 view: function(event) {
668 this.editButton.show();
669 this.editButton.show();
669 this.deleteButton.show();
670 this.deleteButton.show();
670 this.editFields.hide();
671 this.editFields.hide();
671 this.closeButton.hide();
672 this.closeButton.hide();
672 this.viewFields.show();
673 this.viewFields.show();
673 }
674 }
674 };
675 };
675
676
676 var ReviewersPanel = {
677 var ReviewersPanel = {
677 editButton: $('#open_edit_reviewers'),
678 editButton: $('#open_edit_reviewers'),
678 closeButton: $('#close_edit_reviewers'),
679 closeButton: $('#close_edit_reviewers'),
679 addButton: $('#add_reviewer'),
680 addButton: $('#add_reviewer'),
680 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
681 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
681
682
682 init: function() {
683 init: function() {
683 var self = this;
684 var self = this;
684 this.editButton.on('click', function(e) { self.edit(); });
685 this.editButton.on('click', function(e) { self.edit(); });
685 this.closeButton.on('click', function(e) { self.close(); });
686 this.closeButton.on('click', function(e) { self.close(); });
686 },
687 },
687
688
688 edit: function(event) {
689 edit: function(event) {
689 this.editButton.hide();
690 this.editButton.hide();
690 this.closeButton.show();
691 this.closeButton.show();
691 this.addButton.show();
692 this.addButton.show();
692 this.removeButtons.css('visibility', 'visible');
693 this.removeButtons.css('visibility', 'visible');
693 // review rules
694 // review rules
694 reviewersController.loadReviewRules(
695 reviewersController.loadReviewRules(
695 ${c.pull_request.reviewer_data_json | n});
696 ${c.pull_request.reviewer_data_json | n});
696 },
697 },
697
698
698 close: function(event) {
699 close: function(event) {
699 this.editButton.show();
700 this.editButton.show();
700 this.closeButton.hide();
701 this.closeButton.hide();
701 this.addButton.hide();
702 this.addButton.hide();
702 this.removeButtons.css('visibility', 'hidden');
703 this.removeButtons.css('visibility', 'hidden');
703 // hide review rules
704 // hide review rules
704 reviewersController.hideReviewRules()
705 reviewersController.hideReviewRules()
705 }
706 }
706 };
707 };
707
708
708 PRDetails.init();
709 PRDetails.init();
709 ReviewersPanel.init();
710 ReviewersPanel.init();
710
711
711 showOutdated = function(self){
712 showOutdated = function(self){
712 $('.comment-inline.comment-outdated').show();
713 $('.comment-inline.comment-outdated').show();
713 $('.filediff-outdated').show();
714 $('.filediff-outdated').show();
714 $('.showOutdatedComments').hide();
715 $('.showOutdatedComments').hide();
715 $('.hideOutdatedComments').show();
716 $('.hideOutdatedComments').show();
716 };
717 };
717
718
718 hideOutdated = function(self){
719 hideOutdated = function(self){
719 $('.comment-inline.comment-outdated').hide();
720 $('.comment-inline.comment-outdated').hide();
720 $('.filediff-outdated').hide();
721 $('.filediff-outdated').hide();
721 $('.hideOutdatedComments').hide();
722 $('.hideOutdatedComments').hide();
722 $('.showOutdatedComments').show();
723 $('.showOutdatedComments').show();
723 };
724 };
724
725
725 refreshMergeChecks = function(){
726 refreshMergeChecks = function(){
726 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
727 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
727 $('.pull-request-merge').css('opacity', 0.3);
728 $('.pull-request-merge').css('opacity', 0.3);
728 $('.action-buttons-extra').css('opacity', 0.3);
729 $('.action-buttons-extra').css('opacity', 0.3);
729
730
730 $('.pull-request-merge').load(
731 $('.pull-request-merge').load(
731 loadUrl, function() {
732 loadUrl, function() {
732 $('.pull-request-merge').css('opacity', 1);
733 $('.pull-request-merge').css('opacity', 1);
733
734
734 $('.action-buttons-extra').css('opacity', 1);
735 $('.action-buttons-extra').css('opacity', 1);
735 injectCloseAction();
736 injectCloseAction();
736 }
737 }
737 );
738 );
738 };
739 };
739
740
740 injectCloseAction = function() {
741 injectCloseAction = function() {
741 var closeAction = $('#close-pull-request-action').html();
742 var closeAction = $('#close-pull-request-action').html();
742 var $actionButtons = $('.action-buttons-extra');
743 var $actionButtons = $('.action-buttons-extra');
743 // clear the action before
744 // clear the action before
744 $actionButtons.html("");
745 $actionButtons.html("");
745 $actionButtons.html(closeAction);
746 $actionButtons.html(closeAction);
746 };
747 };
747
748
748 closePullRequest = function (status) {
749 closePullRequest = function (status) {
749 // inject closing flag
750 // inject closing flag
750 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
751 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
751 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
752 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
752 $(generalCommentForm.submitForm).submit();
753 $(generalCommentForm.submitForm).submit();
753 };
754 };
754
755
755 $('#show-outdated-comments').on('click', function(e){
756 $('#show-outdated-comments').on('click', function(e){
756 var button = $(this);
757 var button = $(this);
757 var outdated = $('.comment-outdated');
758 var outdated = $('.comment-outdated');
758
759
759 if (button.html() === "(Show)") {
760 if (button.html() === "(Show)") {
760 button.html("(Hide)");
761 button.html("(Hide)");
761 outdated.show();
762 outdated.show();
762 } else {
763 } else {
763 button.html("(Show)");
764 button.html("(Show)");
764 outdated.hide();
765 outdated.hide();
765 }
766 }
766 });
767 });
767
768
768 $('.show-inline-comments').on('change', function(e){
769 $('.show-inline-comments').on('change', function(e){
769 var show = 'none';
770 var show = 'none';
770 var target = e.currentTarget;
771 var target = e.currentTarget;
771 if(target.checked){
772 if(target.checked){
772 show = ''
773 show = ''
773 }
774 }
774 var boxid = $(target).attr('id_for');
775 var boxid = $(target).attr('id_for');
775 var comments = $('#{0} .inline-comments'.format(boxid));
776 var comments = $('#{0} .inline-comments'.format(boxid));
776 var fn_display = function(idx){
777 var fn_display = function(idx){
777 $(this).css('display', show);
778 $(this).css('display', show);
778 };
779 };
779 $(comments).each(fn_display);
780 $(comments).each(fn_display);
780 var btns = $('#{0} .inline-comments-button'.format(boxid));
781 var btns = $('#{0} .inline-comments-button'.format(boxid));
781 $(btns).each(fn_display);
782 $(btns).each(fn_display);
782 });
783 });
783
784
784 $('#merge_pull_request_form').submit(function() {
785 $('#merge_pull_request_form').submit(function() {
785 if (!$('#merge_pull_request').attr('disabled')) {
786 if (!$('#merge_pull_request').attr('disabled')) {
786 $('#merge_pull_request').attr('disabled', 'disabled');
787 $('#merge_pull_request').attr('disabled', 'disabled');
787 }
788 }
788 return true;
789 return true;
789 });
790 });
790
791
791 $('#edit_pull_request').on('click', function(e){
792 $('#edit_pull_request').on('click', function(e){
792 var title = $('#pr-title-input').val();
793 var title = $('#pr-title-input').val();
793 var description = codeMirrorInstance.getValue();
794 var description = codeMirrorInstance.getValue();
794 editPullRequest(
795 editPullRequest(
795 "${c.repo_name}", "${c.pull_request.pull_request_id}",
796 "${c.repo_name}", "${c.pull_request.pull_request_id}",
796 title, description);
797 title, description);
797 });
798 });
798
799
799 $('#update_pull_request').on('click', function(e){
800 $('#update_pull_request').on('click', function(e){
800 $(this).attr('disabled', 'disabled');
801 $(this).attr('disabled', 'disabled');
801 $(this).addClass('disabled');
802 $(this).addClass('disabled');
802 $(this).html(_gettext('Saving...'));
803 $(this).html(_gettext('Saving...'));
803 reviewersController.updateReviewers(
804 reviewersController.updateReviewers(
804 "${c.repo_name}", "${c.pull_request.pull_request_id}");
805 "${c.repo_name}", "${c.pull_request.pull_request_id}");
805 });
806 });
806
807
807 $('#update_commits').on('click', function(e){
808 $('#update_commits').on('click', function(e){
808 var isDisabled = !$(e.currentTarget).attr('disabled');
809 var isDisabled = !$(e.currentTarget).attr('disabled');
809 $(e.currentTarget).attr('disabled', 'disabled');
810 $(e.currentTarget).attr('disabled', 'disabled');
810 $(e.currentTarget).addClass('disabled');
811 $(e.currentTarget).addClass('disabled');
811 $(e.currentTarget).removeClass('btn-primary');
812 $(e.currentTarget).removeClass('btn-primary');
812 $(e.currentTarget).text(_gettext('Updating...'));
813 $(e.currentTarget).text(_gettext('Updating...'));
813 if(isDisabled){
814 if(isDisabled){
814 updateCommits(
815 updateCommits(
815 "${c.repo_name}", "${c.pull_request.pull_request_id}");
816 "${c.repo_name}", "${c.pull_request.pull_request_id}");
816 }
817 }
817 });
818 });
818 // fixing issue with caches on firefox
819 // fixing issue with caches on firefox
819 $('#update_commits').removeAttr("disabled");
820 $('#update_commits').removeAttr("disabled");
820
821
821 $('.show-inline-comments').on('click', function(e){
822 $('.show-inline-comments').on('click', function(e){
822 var boxid = $(this).attr('data-comment-id');
823 var boxid = $(this).attr('data-comment-id');
823 var button = $(this);
824 var button = $(this);
824
825
825 if(button.hasClass("comments-visible")) {
826 if(button.hasClass("comments-visible")) {
826 $('#{0} .inline-comments'.format(boxid)).each(function(index){
827 $('#{0} .inline-comments'.format(boxid)).each(function(index){
827 $(this).hide();
828 $(this).hide();
828 });
829 });
829 button.removeClass("comments-visible");
830 button.removeClass("comments-visible");
830 } else {
831 } else {
831 $('#{0} .inline-comments'.format(boxid)).each(function(index){
832 $('#{0} .inline-comments'.format(boxid)).each(function(index){
832 $(this).show();
833 $(this).show();
833 });
834 });
834 button.addClass("comments-visible");
835 button.addClass("comments-visible");
835 }
836 }
836 });
837 });
837
838
838 // register submit callback on commentForm form to track TODOs
839 // register submit callback on commentForm form to track TODOs
839 window.commentFormGlobalSubmitSuccessCallback = function(){
840 window.commentFormGlobalSubmitSuccessCallback = function(){
840 refreshMergeChecks();
841 refreshMergeChecks();
841 };
842 };
842 // initial injection
843 // initial injection
843 injectCloseAction();
844 injectCloseAction();
844
845
845 ReviewerAutoComplete('#user');
846 ReviewerAutoComplete('#user');
846
847
847 })
848 })
848 </script>
849 </script>
849
850
850 </div>
851 </div>
851 </div>
852 </div>
852
853
853 </%def>
854 </%def>
General Comments 0
You need to be logged in to leave comments. Login now