1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/** Information about a particular waterfall. */
6function WaterfallInfo(waterfallData) {
7  var waterfallName = waterfallData[0];
8  var waterfallUrl = waterfallData[1];
9  var waterfallShowsAllBots = waterfallData[2];
10
11  // Create a table cell that acts as a header for its bot section.
12  var linkElement = document.createElement('a');
13  linkElement.href = waterfallUrl;
14  linkElement.innerHTML = waterfallName;
15  var thElement = document.createElement('th');
16  thElement.colSpan = 15;
17  thElement.className = 'section-header';
18  thElement.appendChild(linkElement);
19
20  this.botInfo = {};
21  this.inFlight = 0;
22  this.name = waterfallName;
23  this.showsAllBots = waterfallShowsAllBots;
24  this.thElement = thElement;
25  this.timeLastRequested = 0;
26  this.rootJsonUrl = waterfallUrl + 'json/';
27  this.url = waterfallUrl;
28}
29
30/** Send an asynchronous request to get the main waterfall's JSON. */
31WaterfallInfo.prototype.requestJson = function() {
32  if (this.inFlight) {
33    var elapsed = new Date().getTime() - this.timeLastRequested;
34    if (elapsed < MAX_MILLISECONDS_TO_WAIT) return;
35
36    // A response was not received in a reasonable timeframe. Try again.
37    this.inFlight--;
38    gNumRequestsInFlight--;
39    gNumRequestsRetried++;
40  }
41
42  this.inFlight++;
43  this.timeLastRequested = new Date().getTime();
44  gNumRequestsInFlight++;
45
46  // Create the request and send it off.
47  var waterfallInfo = this;
48  var url = this.url + 'json/builders/';
49  var request = new XMLHttpRequest();
50  request.open('GET', url, true);
51  request.onreadystatechange = function() {
52    if (request.readyState == 4 && request.status == 200) {
53      waterfallInfo.parseJSON(JSON.parse(request.responseText));
54    }
55  };
56  request.send(null);
57};
58
59/** Parse out the data received about the waterfall. */
60WaterfallInfo.prototype.parseJSON = function(buildersJson) {
61  this.inFlight--;
62  gNumRequestsInFlight--;
63
64  // Go through each builder on the waterfall and get the latest status.
65  var builderNames = Object.keys(buildersJson);
66  for (var i = 0; i < builderNames.length; ++i) {
67    var builderName = builderNames[i];
68
69    if (!this.showsAllBots && !this.shouldShowBot(builderName)) continue;
70
71    // Prepare the bot info.
72    var builderJson = buildersJson[builderName];
73    if (!this.botInfo[builderName]) {
74      this.botInfo[builderName] = new BotInfo(builderName,
75                                              builderJson.category);
76    }
77    this.botInfo[builderName].update(this.rootJsonUrl, builderJson);
78    gWaterfallDataIsDirty = true;
79  }
80};
81
82/** Override this function to filter out particular bots. */
83WaterfallInfo.prototype.shouldShowBot = function(builderName) {
84  return true;
85};
86
87/** Updates the HTML. */
88WaterfallInfo.prototype.updateWaterfallStatusHTML = function() {
89  var table = document.getElementById('build-info');
90
91  // Point at the waterfall.
92  var headerCell = this.thElement;
93  headerCell.className =
94      'section-header' + (this.inFlight > 0 ? ' in-flight' : '');
95  var headerRow = table.insertRow(-1);
96  headerRow.appendChild(headerCell);
97
98  // Print out useful bits about the bots.
99  var botNames = sortBotNamesByCategory(this.botInfo);
100  for (var i = 0; i < botNames.length; ++i) {
101    var botName = botNames[i];
102    var botInfo = this.botInfo[botName];
103    var waterfallBaseUrl = this.url + 'builders/';
104
105    var botRowElement = botInfo.createHtml(waterfallBaseUrl);
106
107    // Determine whether we should apply keyword filter.
108    var filter = document.getElementById('text-filter').value.trim();
109    if (filter.length > 0) {
110      var keywords = filter.split(' ');
111      var buildNumbers = Object.keys(botInfo.builds);
112      var matchesFilter = false;
113
114      for (var x = 0; x < buildNumbers.length && !matchesFilter; ++x) {
115        var buildStatus = botInfo.builds[buildNumbers[x]].statusText;
116        for (var y = 0; y < keywords.length && !matchesFilter; ++y) {
117          if (buildStatus.indexOf(keywords[y]) >= 0)
118            matchesFilter = true;
119        }
120      }
121
122      if (!matchesFilter)
123        continue;
124    }
125
126    // If the user doesn't want to see completely green bots, hide it.
127    var shouldHideStable =
128        document.getElementById('checkbox-hide-stable').checked;
129    if (shouldHideStable && botInfo.isSteadyGreen)
130      continue;
131
132    table.appendChild(botRowElement);
133  }
134};
135