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