Passed
Push — master ( 62d7d9...8230b1 )
by Alexander
03:29
created

tcms/static/js/testrun_actions.js (1 issue)

Check to flag variables that are implicitly global.

Bug Major
1
Nitrate.TestRuns = {};
2
Nitrate.TestRuns.Details = {};
3
Nitrate.TestRuns.Execute = {}
4
Nitrate.TestRuns.AssignCase = {}
5
6
7
function toggleDiv(link, divId) {
8
  var link = jQ(link);
9
  var div = jQ('#' + divId);
10
  var show = 'Show All';
11
  var hide = 'Hide All';
12
  div.toggle();
13
  var text = link.html();
14
  if (text !== show) {
15
    link.html(show);
16
  } else {
17
    link.html(hide);
18
  }
19
}
20
21
22
Nitrate.TestRuns.Details.on_load = function() {
23
  setAddTagAutocomplete();
24
25
  // Observe the interface buttons
26
  jQ('#id_check_all_button').bind('click', function(e) {
27
    toggleAllCheckBoxes(this, 'id_table_cases', 'case_run');
28
  });
29
30
  if (jQ('#id_check_box_highlight').attr('checked')) {
31
    jQ('.mine').addClass('highlight');
32
  }
33
34
  jQ('#id_check_box_highlight').bind('click', function(e) {
35
    e = jQ('.mine');
36
    this.checked && e.addClass('highlight') || e.removeClass('highlight');
37
  });
38
39
  jQ('#id_blind_all_link').bind('click', function(e) {
40
    if (!jQ('td[id^="id_loading_"]').length) {
41
      jQ(this).removeClass('locked');
42
    }
43
    if (jQ(this).is('.locked')) {
44
      //To disable the 'expand all' until all case runs are expanded.
45
      return false;
46
    } else {
47
      jQ(this).addClass('locked');
48
      var element = jQ(this).children();
49
      if (element.is('.collapse-all')) {
50
        this.title = "Collapse all cases";
51
        blinddownAllCases(element[0]);
52
      } else {
53
        this.title = "Expand all cases";
54
        blindupAllCases(element[0]);
55
      }
56
    }
57
  });
58
59
  // Observe the case run toggle and the comment form
60
  var toggle_case_run = function(e) {
61
    var c = jQ(this).parent(); // Container
62
    var c_container = c.next(); // Content Containers
63
    var case_id = c.find('input[name="case"]')[0].value;
64
    var case_run_id = c.find('input[name="case_run"]')[0].value;
65
    var case_text_version = c.find('input[name="case_text_version"]')[0].value;
66
    var type = 'case_run';
67
    var callback = function(t) {
68
      // Observe the update case run stauts/comment form
69
      c_container.parent().find('.update_form')
70
        .unbind('submit').bind('submit', updateCaseRunStatus);
71
72
      // Observe the delete comment form
73
      var refresh_case = function(t) {
74
        constructCaseRunZone(c_container[0], c[0], case_id);
75
      };
76
77
      var rc_callback = function(e) {
78
        e.stopPropagation();
79
        e.preventDefault();
80
        if (!window.confirm(default_messages.confirm.remove_comment)) {
81
          return false;
82
        }
83
        removeComment(this, refresh_case);
84
      };
85
      c_container.parent().find('.form_comment')
86
        .unbind('submit').bind('submit', rc_callback);
87
      c_container.find('.js-status-button').bind('click', function() {
88
        this.form.value.value = jQ(this).data('formvalue');
89
      });
90
      c_container.find('.js-show-comments').bind('click', function() {
91
        toggleDiv(this, jQ(this).data('param'));
92
      });
93
      c_container.find('.js-show-changelog').bind('click', function() {
94
        toggleDiv(this, jQ(this).data('param'));
95
      });
96
      c_container.find('.js-file-caserun-bug').bind('click', function(){
97
        var params = jQ(this).data('params');
98
        fileCaseRunBug(params[0], c[0], c_container[0], params[1], params[2]);
99
      });
100
      c_container.find('.js-add-caserun-bug').bind('click', function(){
101
        var params = jQ(this).data('params');
102
        addCaseRunBug(params[0], c[0], c_container[0], params[1], params[2]);
103
      });
104
      c_container.find('.js-remove-caserun-bug').bind('click', function(){
105
        var params = jQ(this).data('params');
106
        removeCaseBug(params[1], params[2], params[3]);
107
      });
108
      c_container.find('.js-add-testlog').bind('click', function(){
109
        var params = jQ(this).data('params');
110
        addLinkToTestExecution(this, params[0], [params[1]]);
111
      });
112
      c_container.find('.js-remove-testlog').bind('click', function(){
113
        var button = this;
114
        jsonRPC('TestExecution.remove_link', [{pk: $(button).data('param')}], function(result) {
115
            button.parentNode.remove();
116
        });
117
      });
118
    };
119
120
    toggleTestExecutionPane({
121
      'callback': callback,
122
      'caseId': case_id,
123
      'caserunId': case_run_id,
124
      'caseTextVersion': case_text_version,
125
      'caserunRowContainer': c,
126
      'expandPaneContainer': c_container
127
    });
128
  };
129
  jQ('.expandable').bind('click', toggle_case_run);
130
131
  // Auto show the case run contents.
132
  if (window.location.hash != '') {
133
    fireEvent(jQ('a[href=\"' + window.location.hash + '\"]')[0], 'click');
134
  };
135
136
  // Filter Case-Run
137
  if (jQ('#filter_case_run').length) {
138
    jQ('#filter_case_run').bind('click',function(e){
139
      if (jQ('#id_filter').is(':hidden')){
140
        jQ('#id_filter').show();
141
        jQ(this).html(default_messages.link.hide_filter);
142
      } else {
143
        jQ('#id_filter').hide();
144
        jQ(this).html(default_messages.link.show_filter);
145
      }
146
    });
147
  }
148
  //bind click to status btn
149
  jQ('.btn_status').live('click', function() {
150
    var from = jQ(this).siblings('.btn_status:disabled')[0].title;
151
    var to = this.title;
152
    if (jQ('span#' + to + ' a').text() === '0') {
153
      var htmlstr = "[<a href='javascript:void(0)' onclick=\"showCaseRunsWithSelectedStatus(jQ('#id_filter')[0], '"
154
        + jQ(this).attr('crs_id')+"')\">0</a>]";
155
      jQ('span#' + to).html(htmlstr);
156
    }
157
    if (jQ('span#' + from + ' a').text() === '1') {
158
      jQ('span#' + from).html("[<a>1</a>]");
159
    }
160
    jQ('span#' + to + ' a').text(window.parseInt(jQ('span#' + to + ' a').text()) + 1);
161
    jQ('span#' + from + ' a').text(window.parseInt(jQ('span#' + from + ' a').text()) - 1);
162
163
    var caseRunCount = window.parseInt(jQ('span#TOTAL').next().text()) || 0;
164
    var passedCaseRunCount = window.parseInt(jQ('span#PASSED a').text()) || 0;
165
    var errorCaseRunCount = window.parseInt(jQ('span#ERROR a').text()) || 0;
166
    var failedCaseRunCount = window.parseInt(jQ('span#FAILED a').text()) || 0;
167
    var waivedCaseRunCount = window.parseInt(jQ('span#WAIVED a').text()) || 0;
168
    var completePercent = 100 * ((passedCaseRunCount + errorCaseRunCount + failedCaseRunCount
169
      + waivedCaseRunCount) / caseRunCount).toFixed(2);
170
    var failedPercent = 100 * ((errorCaseRunCount + failedCaseRunCount) / (passedCaseRunCount
171
      + errorCaseRunCount + failedCaseRunCount + waivedCaseRunCount)).toFixed(2);
172
173
    jQ('span#complete_percent').text(completePercent);
174
    jQ('div.progress-inner').attr('style', 'width:' + completePercent + '%');
175
    jQ('div.progress-failed').attr('style', 'width:' + failedPercent + '%');
176
  });
177
178
  jQ('#btn_clone').bind('click', function() {
179
    postToURL(jQ(this).data('param'), serializeCaseRunFromInputList('id_table_cases','case_run'));
180
  });
181
  jQ('#btn_delete').bind('click', function() {
182
    window.location.href = jQ(this).data('param');
183
  });
184
185
  bindJSRemoveTagButton();
186
  jQ('.js-add-tag').bind('click', function() {
187
    addRunTag(jQ('.js-tag-ul')[0], jQ(this).data('param'));
188
  });
189
  jQ('.js-set-running').bind('click', function() {
190
    window.location.href = jQ(this).data('param') + '?finished=0';
191
  });
192
  jQ('.js-set-finished').bind('click', function() {
193
    window.location.href = jQ(this).data('param') + '?finished=1';
194
  });
195
  jQ('.js-del-case').bind('click', function() {
196
    delCaseRun(jQ(this).data('param'));
197
  });
198
  jQ('.js-update-case').bind('click', function() {
199
    postToURL(jQ(this).data('param'), serializeCaseRunFromInputList('id_table_cases', 'case_run'));
200
  });
201
  jQ('.js-change-assignee').bind('click', function() {
202
    changeCaseRunAssignee();
203
  });
204
  jQ('.js-add-bugs').bind('click', function() {
205
    updateBugs('add');
206
  });
207
  jQ('.js-remove-bugs').bind('click', function() {
208
    updateBugs('remove');
209
  });
210
  jQ('.js-show-commentdialog').bind('click', function() {
211
    showCommentForm();
212
  });
213
214
    $('.js-add-links').bind('click', function() {
215
        bulkAddLinkToTestExecution();
216
    });
217
218
  jQ('.js-add-cc').bind('click', function() {
219
    addRunCC(jQ(this).data('param'), jQ('.js-cc-ul')[0]);
220
  });
221
  jQ('.js-remove-cc').bind('click', function() {
222
    var params = jQ(this).data('params');
223
    removeRunCC(params[0], params[1], jQ('.js-cc-ul')[0]);
224
  });
225
  jQ('.js-caserun-total').bind('click', function() {
226
    showCaseRunsWithSelectedStatus(jQ('#id_filter')[0], '');
227
  });
228
  jQ('.js-status-subtotal').bind('click', function() {
229
    showCaseRunsWithSelectedStatus(jQ('#id_filter')[0], jQ(this).data('param'));
230
  });
231
};
232
233
Nitrate.TestRuns.AssignCase.on_load = function() {
234
  if (jQ('#id_check_all_button').length) {
235
    jQ('#id_check_all_button').bind('click', function(m) {
236
      toggleAllCheckBoxes(this, 'id_table_cases', 'case');
237
    });
238
  }
239
240
  jQ('input[name="case"]').bind('click', function(t) {
241
    if (this.checked) {
242
      jQ(this).closest('tr').addClass('selection_row');
243
      jQ(this).parent().siblings().eq(7).html('<div class="apply_icon"></div>');
244
    } else {
245
      jQ(this).closest('tr').removeClass('selection_row');
246
      jQ(this).parent().siblings().eq(7).html('');
247
    }
248
  });
249
250
  jQ('.js-how-assign-case').bind('click', function() {
251
    jQ('#help_assign').show();
252
  });
253
  jQ('.js-close-how-assign').bind('click', function() {
254
    jQ('#help_assign').hide();
255
  });
256
  jQ('.js-toggle-button, .js-case-summary').bind('click', function() {
257
    toggleTestCaseContents(jQ(this).data('param'));
258
  });
259
};
260
261
262
function updateRunStatus(object_pk, value, callback) {
263
  jQ.ajax({
264
    'url': '/runs/case-run-update-status/',
265
    'type': 'POST',
266
    'data': {'object_pk': object_pk, 'status_id': value },
267
    'success': function (data, textStatus, jqXHR) {
268
      callback();
269
    },
270
    'error': function (jqXHR, textStatus, errorThrown) {
271
      json_failure(jqXHR);
272
    }
273
  });
274
}
275
276
var updateCaseRunStatus = function(e) {
277
  e.stopPropagation();
278
  e.preventDefault();
279
  var container = jQ(this).parents().eq(3);
280
  var parent = container.parent();
281
  var title = parent.prev();
282
  var link = title.find('.expandable')[0];
283
  var parameters = Nitrate.Utils.formSerialize(this);
284
  var object_pk = parameters['object_pk'];
285
  var value = parameters['value'];
286
287
  // Callback when
288
  var callback = function(t) {
289
    // Update the contents
290
    if (parameters['value'] != '') {
291
      // Update the case run status icon
292
      var crs = Nitrate.TestRuns.CaseRunStatus;
293
      title.find('.icon_status').each(function(index) {
294
        for (i in crs) {
295
          if (typeof crs[i] === 'string' && jQ(this).is('.btn_' + crs[i])) {
296
            jQ(this).removeClass('btn_' + crs[i]);
297
          }
298
        }
299
        jQ(this).addClass('btn_' + Nitrate.TestRuns.CaseRunStatus[value - 1]);
300
      });
301
302
      // Update related people
303
      var usr = Nitrate.User;
304
      title.find('.link_tested_by').each(function(i) {
305
        jQ(this).html(usr.username);
306
      });
307
    }
308
309
    // Mark the case run to mine
310
    if (!title.is('.mine')) {
311
      title.addClass('mine');
312
    }
313
314
    // Blind down next case
315
    fireEvent(link, 'click');
316
    if (jQ('#id_check_box_auto_blinddown').attr('checked') && parameters['value'] != '') {
317
      var next_title = parent.next();
318
      if (!next_title.length) {
319
        return false;
320
      }
321
      if (next_title.next().is(':hidden')) {
322
        fireEvent(next_title.find('.expandable')[0], 'click');
323
      }
324
    } else {
325
      fireEvent(link, 'click');
326
    }
327
  };
328
329
  // Add comment
330
  if (parameters['comment'] != '') {
331
    // Reset the content to loading
332
    var ajax_loading = getAjaxLoading();
333
    ajax_loading.id = 'id_loading_' + parameters['case_id'];
334
    container.html(ajax_loading);
335
    var c = jQ('<div>');
336
    if (parameters['value'] != '') {
337
      submitComment(c[0], parameters);
338
    } else {
339
      submitComment(c[0], parameters, callback);
340
    }
341
  }
342
343
  // Update the object when changing the status
344
  if (parameters['value'] != '') {
345
    // Reset the content to loading
346
    var ajax_loading = getAjaxLoading();
347
    ajax_loading.id = 'id_loading_' + parameters['case_id'];
348
    container.html(ajax_loading);
349
    updateRunStatus([object_pk], value, callback);
350
  }
351
};
352
353
354
function constructCaseRunZone(container, title_container, case_id) {
355
  var link = jQ(title_container).find('.expandable')[0];
356
  if (container) {
357
    var td = jQ('<td>', {'id': 'id_loading_' + case_id, 'colspan': 12 });
358
    td.html(getAjaxLoading());
359
    jQ(container).html(td);
360
  }
361
362
  if (title_container) {
363
    fireEvent(link, 'click');
364
    fireEvent(link, 'click');
365
  }
366
}
367
368
369
//////////////////////////////////////////////////////////////////////////////////////////////
370
////////   AddIssueDialog Definition //////////////
371
372
373
/*
374
 * Dialog to allow user to add sort of issue keys to case run(s).
375
 *
376
 * Here, issue key is a general to whatever the issue tracker system is.
377
 *
378
 * options:
379
 * @param extraFormHiddenData: used for providing extra data for specific AJAX request.
380
 * @param onSubmit: callback function when user click Add button
381
 * @param action: string - Add or Remove. Default is Add
382
 */
383
/*
384
 * FIXME: which namespace is proper to hold this dialog class?
385
 */
386
function AddIssueDialog(options) {
387
  this.onSubmit = options.onSubmit;
388
  if (this.onSubmit !== undefined && typeof this.onSubmit !== "function") {
389
    throw new Error("onSubmit should be a function object.");
390
  }
391
  this.extraFormHiddenData = options.extraFormHiddenData;
392
  if (this.extraFormHiddenData !== undefined && typeof this.extraFormHiddenData !== "object") {
393
    throw new Error("extraFormHiddenData sould be an object if present.");
394
  }
395
396
  this.action = options.action;
397
  if (this.action === undefined) {
398
    this.action = "Add";
399
  }
400
401
  this.a = options.a;
402
  if (this.a === undefined) {
403
    this.a = this.action.toLowerCase();
404
  }
405
406
  if (options.hasOwnProperty("show_bug_id_field")) {
407
    this.show_bug_id_field = options.show_bug_id_field;
408
  } else {
409
    this.show_bug_id_field = false;
410
  }
411
}
412
413
414
AddIssueDialog.prototype.show = function () {
415
  var dialog = jQ("#dialog")[0];
416
  if (dialog == null) {
417
    throw new Error("No HTML element with ID dialog. This should not happen in the runtime.");
418
  }
419
420
  var hiddenPart = [];
421
  if (this.extraFormHiddenData !== undefined) {
422
    for (var name_attr in this.extraFormHiddenData) {
423
      hiddenPart.push({'name': name_attr, 'value': this.extraFormHiddenData[name_attr]});
424
    }
425
  }
426
427
  var template = Handlebars.compile(jQ("#add_issue_form_template").html());
428
  var context = {
429
    'hiddenFields': hiddenPart,
430
    'action_button_text': this.action,
431
    'show_bug_id_field': this.show_bug_id_field || this.action === 'Add',
432
    'show_add_to_bugzilla_checkbox': this.action === 'Add',
433
    'a': this.a,
434
  };
435
436
  jQ('#dialog').html(template(context))
437
    .find('.js-cancel-button').bind('click', function() {
438
      jQ('#dialog').hide();
439
    })
440
    .end().show();
441
442
  this.form = jQ("#add_issue_form")[0];
443
444
  // Used for following event callbacks to ref this dialog's instance
445
  var that = this;
446
447
  // Set custom callback functions
448
  if (this.onSubmit !== undefined) {
449
    jQ(this.form).bind('submit', function (form_event) {
450
      that.onSubmit(form_event, that);
451
    });
452
  }
453
};
454
455
AddIssueDialog.prototype.get_data = function () {
456
  var form_data = Nitrate.Utils.formSerialize(this.form);
457
  form_data.bug_validation_regexp = $('#bug_system_id option:selected').data('validation-regexp');
458
  form_data.bz_external_track = $('input[name=bz_external_track]').is(':checked');
459
  return form_data;
460
};
461
462
//// end of AddIssueDialog definition /////////
463
/////////////////////////////////////////////////////////////////////////////////////////////
464
465
function fileCaseRunBug(run_id, title_container, container, case_id, case_run_id) {
466
  var dialog = new AddIssueDialog({
467
    'action': 'Report',
468
    'onSubmit': function (e, dialog) {
469
      e.stopPropagation();
470
      e.preventDefault();
471
472
        var tracker_id = dialog.get_data()['bug_system_id'];
473
        jsonRPC('Bug.report', [case_run_id, tracker_id], function(result) {
474
            $('#dialog').hide();
475
476
            if (result.rc === 0) {
477
                window.open(result.response, '_blank');
478
            } else {
479
                window.alert(result.response);
480
            }
481
      });
482
    }
483
  });
484
485
  dialog.show();
486
}
487
488
function addCaseRunBug(run_id, title_container, container, case_id, case_run_id) {
489
  var dialog = new AddIssueDialog({
490
    'onSubmit': function (e, dialog) {
491
      e.stopPropagation();
492
      e.preventDefault();
493
494
      form_data = dialog.get_data();
0 ignored issues
show
The variable form_data seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.form_data.
Loading history...
495
496
      form_data.bug_id = form_data.bug_id.trim();
497
      if (!form_data.bug_id.length) {
498
        return;
499
      }
500
501
        jsonRPC('Bug.create', [{
502
                case_id: case_id,
503
                case_run_id: case_run_id,
504
                bug_id: form_data.bug_id,
505
                bug_system_id: form_data.bug_system_id
506
            }, form_data.bz_external_track],
507
            function(result) {
508
                // todo: missing error handling when bz_external_track is true
509
                $('#dialog').hide();
510
511
                // Update bugs count associated with just updated case run
512
                var jqCaserunBugCount = $('span#' + case_run_id + '_case_bug_count');
513
                jqCaserunBugCount.addClass('have_bug');
514
515
                // refresh the links of bugs
516
                constructCaseRunZone(container, title_container, case_id);
517
        });
518
    }
519
  });
520
521
  dialog.show();
522
}
523
524
525
function delCaseRun(run_id) {
526
    if (window.confirm('Are you sure?')) {
527
        const executions = $('#id_table_cases').find('input[name="case_run"]:checked');
528
529
        executions.each(function() {
530
            var case_id = this.getAttribute('data-case_id');
531
            jsonRPC('TestRun.remove_case', [run_id, Number(case_id)], function () {
532
                $(this).closest('tr').remove();
533
            }.bind(this));
534
        });
535
    }
536
}
537
538
539
// binds the remove buttons for all tags
540
function bindJSRemoveTagButton() {
541
  $('.js-remove-tag').bind('click', function() {
542
    var params = $(this).data('params');
543
    removeRunTag($('.js-tag-ul')[0], params[0], params[1]);
544
  });
545
}
546
547
548
// data is an array of id/name for tags
549
function updateTagContainer(container, data, run_id) {
550
    var html = '';
551
552
    data.forEach(function(element) {
553
        var li = '<li>' + element['name'] +
554
                    '<a href="#" class="js-remove-tag" data-params=\'["'+ run_id + '", "' + element['name'] + '"]\'>' +
555
                        '&nbsp;<i class="fa fa-trash-o"></i>' +
556
                    '</a>' +
557
                 '</li>';
558
        html += li;
559
    });
560
561
    $(container).html(html);
562
    bindJSRemoveTagButton();
563
}
564
565
566
function addRunTag(container, run_id) {
567
    var tag_container = $('#id_tags');
568
    var tag = tag_container.val();
569
570
    if (!tag) {
571
        return false;
572
    }
573
574
    var inner_callback = function(data) {
575
        updateTagContainer(container, data, run_id);
576
        tag_container.val('');
577
    }
578
    jsonRPC('TestRun.add_tag', [run_id, tag], inner_callback);
579
}
580
581
function removeRunTag(container, run_id, tag) {
582
    var inner_callback = function(data) {
583
        updateTagContainer(container, data, run_id);
584
    }
585
    jsonRPC('TestRun.remove_tag', [run_id, tag], inner_callback);
586
}
587
588
function constructRunCC(container, run_id, parameters) {
589
  var complete = function(t) {
590
    jQ('.js-remove-cc').bind('click', function() {
591
      var params = jQ(this).data('params');
592
      removeRunCC(params[0], params[1], jQ('.js-cc-ul')[0]);
593
    });
594
    if (jQ('#message').length) {
595
      window.alert(jQ('#message').html());
596
      return false;
597
    }
598
  };
599
  var url = '/runs/' + run_id + '/cc/';
600
  jQ.ajax({
601
    'url': url,
602
    'type': 'GET',
603
    'data': parameters,
604
    'success': function (data, textStatus, jqXHR) {
605
      jQ(container).html(data);
606
    },
607
    'complete': function() {
608
      complete();
609
    }
610
  });
611
}
612
613
function addRunCC(run_id, container) {
614
  var user = window.prompt('Please type new email or username for CC.');
615
  if (!user) {
616
    return false;
617
  }
618
  var parameters = {'do': 'add', 'user': user};
619
  constructRunCC(container, run_id, parameters);
620
}
621
622
function removeRunCC(run_id, user, container) {
623
  var c = window.confirm('Are you sure to delete this user from CC?');
624
625
  if (!c) {
626
    return false;
627
  }
628
629
  var parameters = { 'do': 'remove', 'user': user };
630
  constructRunCC(container, run_id, parameters);
631
}
632
633
function changeCaseRunAssignee() {
634
  var runs = serializeCaseRunFromInputList(jQ('#id_table_cases')[0]);
635
  if (!runs.length) {
636
    window.alert(default_messages.alert.no_case_selected);
637
    return false;
638
  }
639
640
  var p = window.prompt('Please type new email or username for assignee');
641
  if (!p) {
642
    return false;
643
  }
644
645
  jQ.ajax({
646
    'url': '/runs/update-assignee/',
647
    'type': 'POST',
648
    'data': { ids: runs, assignee: p },
649
    'success': function (data, textStatus, jqXHR) {
650
      window.location.reload();
651
    },
652
    'error': function (jqXHR, textStatus, errorThrown) {
653
      json_failure(jqXHR);
654
    }
655
  });
656
}
657
658
function serializeCaseRunFromInputList(table, name) {
659
  var elements;
660
  if (typeof table === 'string') {
661
    elements = jQ('#' + table).parent().find('input[name="case_run"]:checked');
662
  } else {
663
    elements = jQ(table).parent().find('input[name="case_run"]:checked');
664
  }
665
666
  var returnobj_list = [];
667
  elements.each(function(i) {
668
    if (typeof this.value === 'string') {
669
      returnobj_list.push(this.value);
670
    }
671
  });
672
  if (name) {
673
    var returnobj = {};
674
    returnobj[name] = returnobj_list;
675
    return returnobj;
676
  }
677
678
  return returnobj_list;
679
}
680
681
function serialzeCaseForm(form, table, serialized) {
682
  if (typeof serialized !== 'boolean') {
683
    var serialized = true;
684
  }
685
  var data;
686
  if (serialized) {
687
    data = Nitrate.Utils.formSerialize(form);
688
  } else {
689
    data = jQ(form).serialize();
690
  }
691
692
  data['case_run'] = serializeCaseFromInputList(table);
693
  return data;
694
}
695
696
function showCaseRunsWithSelectedStatus(form, status_id) {
697
  form.status__pk.value = status_id;
698
  fireEvent(jQ(form).find('input[type="submit"]')[0], 'click');
699
}
700
701
function updateBugsActionAdd(case_runs) {
702
  var dialog = new AddIssueDialog({
703
    'extraFormHiddenData': { 'case_runs': case_runs.join() },
704
    'onSubmit': function(e, dialog) {
705
      e.stopPropagation();
706
      e.preventDefault();
707
      var form_data = dialog.get_data();
708
      form_data.bug_id = form_data.bug_id.trim();
709
710
      if (!form_data.bug_id.length) {
711
        return;
712
      }
713
714
      if (!validateIssueID(form_data.bug_validation_regexp, form_data.bug_id)) {
715
        return false;
716
      }
717
718
      jQ.ajax({
719
        url: '/caserun/update-bugs-for-many/',
720
        dataType: 'json',
721
        data: form_data,
722
        success: function(res){
723
          if (res.rc === 0) {
724
            reloadWindow();
725
          } else {
726
            window.alert(res.response);
727
            return false;
728
          }
729
        }
730
      });
731
    }
732
  });
733
  dialog.show();
734
}
735
736
function updateBugsActionRemove(case_runs) {
737
  var dialog = new AddIssueDialog({
738
    'action': 'Remove',
739
    'show_bug_id_field': true,
740
    'extraFormHiddenData': { 'case_runs': case_runs.join() },
741
    'onSubmit': function(e, dialog) {
742
      e.stopPropagation();
743
      e.preventDefault();
744
      var form_data = dialog.get_data();
745
      form_data.bug_id = form_data.bug_id.trim();
746
747
      if (!form_data.bug_id.length) {
748
        return;
749
      }
750
751
      if (!validateIssueID(form_data.bug_validation_regexp, form_data.bug_id)) {
752
        return false;
753
      }
754
755
      jQ.ajax({
756
        url: '/caserun/update-bugs-for-many/',
757
        dataType: 'json',
758
        success: function(res) {
759
          if (res.rc == 0) {
760
            reloadWindow();
761
          } else {
762
            window.alert(res.response);
763
            return false;
764
          }
765
        },
766
        data: form_data,
767
      });
768
    }
769
  });
770
  dialog.show();
771
}
772
773
function updateBugs(action) {
774
  var runs = serializeCaseRunFromInputList(jQ('#id_table_cases')[0]);
775
  if (!runs.length) {
776
    window.alert(default_messages.alert.no_case_selected);
777
    return false;
778
  }
779
780
  if (action === "add") {
781
    updateBugsActionAdd(runs);
782
  } else if (action === "remove") {
783
    updateBugsActionRemove(runs);
784
  } else {
785
    throw new Error("Unknown operation when update case runs' bugs. This should not happen.");
786
  }
787
}
788
789
function showCommentForm() {
790
  var dialog = getDialog();
791
  var runs = serializeCaseRunFromInputList(jQ('#id_table_cases')[0]);
792
  if (!runs.length) {
793
    return window.alert(default_messages.alert.no_case_selected);
794
  }
795
  var template = Handlebars.compile(jQ("#batch_add_comment_to_caseruns_template").html());
796
  jQ(dialog).html(template());
797
798
  var commentText = jQ('#commentText');
799
  var commentsErr = jQ('#commentsErr');
800
  jQ('#btnComment').live('click', function() {
801
    var error;
802
    var comments = jQ.trim(commentText.val());
803
    if (!comments) {
804
      error = 'No comments given.';
805
    }
806
    if (error) {
807
      commentsErr.html(error);
808
      return false;
809
    }
810
    jQ.ajax({
811
      url: '/caserun/comment-many/',
812
      data: {'comment': comments, 'run': runs.join()},
813
      dataType: 'json',
814
      type: 'post',
815
      success: function(res) {
816
        if (res.rc == 0) {
817
          reloadWindow();
818
        } else {
819
          commentsErr.html(res.response);
820
          return false;
821
        }
822
      }
823
    });
824
  });
825
  jQ('#btnCancelComment').live('click', function(){
826
    jQ(dialog).hide();
827
    commentText.val('');
828
  });
829
  jQ(dialog).show();
830
}
831
832
jQ(document).ready(function(){
833
  jQ('.btnBlueCaserun').mouseover(function() {
834
    jQ(this).find('ul').show();
835
  }).mouseout(function() {
836
    jQ(this).find('ul').hide();
837
  });
838
  jQ('ul.statusOptions a').click(function() {
839
    var option = jQ(this).attr('value');
840
    var object_pks = serializeCaseRunFromInputList(jQ('#id_table_cases')[0]);
841
    if (option == '') {
842
      return false;
843
    }
844
    if (!object_pks.length) {
845
      window.alert(default_messages.alert.no_case_selected);
846
      return false;
847
    }
848
    if (!window.confirm(default_messages.confirm.change_case_status)) {
849
      return false;
850
    }
851
    updateRunStatus(object_pks, option, reloadWindow);
852
  });
853
});
854
855
856
function bulkAddLinkToTestExecution() {
857
    var execution_ids = serializeCaseRunFromInputList(jQ('#id_table_cases')[0]);
858
    if (!execution_ids.length) {
859
        return window.alert(default_messages.alert.no_case_selected);
860
    }
861
862
    addLinkToTestExecution(null, null, execution_ids);
863
}
864
865
/*
866
 * - sender: the Add link button, which is pressed to fire this event.
867
 * - case_id: used for reloading TE details. In case of bulk actions this
868
 *            is null/undefined and the entire page is reloaded!
869
 * - execution_ids: Array of TestExecution IDs to which the new link will be added
870
 */
871
function addLinkToTestExecution(sender, case_id, execution_ids) {
872
  var dialog_p = jQ('#addlink_dialog');
873
874
  dialog_p.dialog('option', 'target_id', execution_ids);
875
  dialog_p.dialog('option', 'case_id', case_id);
876
  if (case_id) {
877
      // These two options are used for reloading TestExecution when successfully.
878
      var container = jQ(sender).parents('.case_content.hide')[0];
879
      dialog_p.dialog('option', 'container', container);
880
      var title_container = jQ(container).prev()[0];
881
      dialog_p.dialog('option', 'title_container', title_container);
882
  }
883
  dialog_p.dialog('open');
884
}
885
886
/*
887
 * Initialize dialog for getting information about new link, which is attached
888
 * to an arbitrary instance of TestExecution
889
 */
890
function initialize_addlink_dialog() {
891
  var dialog_p = jQ('#addlink_dialog');
892
893
  dialog_p.dialog({
894
    autoOpen: false,
895
    modal: true,
896
    resizable: false,
897
    height: 300,
898
    width: 400,
899
    open: function() {
900
      jQ(this).unbind('submit').bind('submit', function (e) {
901
        e.stopPropagation();
902
        e.preventDefault();
903
        jQ(this).dialog('widget').find('span:contains("OK")').click();
904
      });
905
    },
906
    buttons: {
907
      "OK": function() {
908
        var name = jQ('#testlog_name').attr('value');
909
        var url = jQ('#testlog_url').attr('value');
910
        var case_id = dialog_p.dialog('option', 'case_id');
911
912
        dialog_p.dialog('close');
913
914
        jQ(this).dialog('option', 'target_id').forEach(function(target_id) {
915
            jsonRPC('TestExecution.add_link', [target_id, name, url], function(result) {
916
                // when bulk adding links case_id will be undefined/null
917
                if (case_id) {
918
                    // Begin to construct case run area
919
                    var container = dialog_p.dialog('option', 'container');
920
                    var title_container = dialog_p.dialog('option', 'title_container');
921
                    constructCaseRunZone(container, title_container, case_id);
922
                }
923
            });
924
        });
925
926
        // reload entire page if adding in bulk
927
        if (!case_id) {
928
            window.location.reload(true);
929
        }
930
      },
931
      "Cancel": function() {
932
        jQ(this).dialog('close');
933
      }
934
    },
935
    beforeClose: function() {
936
      // clean name and url for next input
937
      jQ('#testlog_name').val('');
938
      jQ('#testlog_url').val('');
939
940
      return true;
941
    },
942
    /* ATTENTION: target_id can be determined when open this dialog, and
943
     * this must be set
944
     */
945
    target_id: null
946
  });
947
}
948
949
950
/*
951
 * Toggle TestExecution panel to edit a case run in run page.
952
 *
953
 * Arguments:
954
 * options.casrunContainer:
955
 * options.expandPaneContainer:
956
 * options.caseId:
957
 * options.caserunId:
958
 * options.caseTextVersion:
959
 * options.callback:
960
 */
961
function toggleTestExecutionPane(options) {
962
  var container = options.caserunRowContainer;
963
  var content_container = options.expandPaneContainer;
964
  var callback = options.callback;
965
966
  content_container.toggle();
967
968
  if (content_container.find('.ajax_loading').length) {
969
    var url = '/case/' + options.caseId + '/execution-detail-pane/';
970
    var data = { case_run_id: options.caserunId, case_text_version: options.caseTextVersion };
971
972
    jQ.get(url, data, function(data, textStatus) {
973
      content_container.html(data);
974
      callback();
975
    }, 'html');
976
  }
977
978
  toggleExpandArrow({ caseRowContainer: container, expandPaneContainer: content_container });
979
}
980