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