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/** Random constants. */
6var MAX_BUILD_STATUS_LENGTH = 50;
7var TICKS_BETWEEN_REFRESHES = 60;
8var NUM_PREVIOUS_BUILDS_TO_SHOW = 3;
9var MAX_MILLISECONDS_TO_WAIT = 5 * 60 * 1000;
10
11/** Parsed JSON data. */
12var gWaterfallData = [];
13var gStatusData = [];
14var gWaterfallDataIsDirty = true;
15
16/** Global state. */
17var gTicksUntilRefresh = TICKS_BETWEEN_REFRESHES;
18
19/** Statistics. */
20var gNumRequestsInFlight = 0;
21var gNumRequestsIgnored = 0;
22var gNumRequestsRetried = 0;
23var gStartTimestamp = 0;
24
25/** Cut the status message down so it doesn't hog the whole screen. */
26function truncateStatusText(text) {
27  if (text.length > MAX_BUILD_STATUS_LENGTH) {
28    return text.substr(0, MAX_BUILD_STATUS_LENGTH) + '...';
29  }
30  return text;
31}
32
33/** Queries all of the servers for their latest statuses. */
34function queryServersForInfo() {
35  for (var index = 0; index < gWaterfallData.length; ++index) {
36    gWaterfallData[index].requestJson();
37  }
38
39  for (var index = 0; index < gStatusData.length; ++index) {
40    gStatusData[index].requestJson();
41  }
42}
43
44/** Updates the sidebar's contents. */
45function updateSidebarHTML() {
46  // Update all of the project info.
47  var divElement = document.getElementById('sidebar-contents');
48  while (divElement.firstChild) {
49    divElement.removeChild(divElement.firstChild);
50  }
51
52  for (var i = 0; i < gStatusData.length; ++i) {
53    divElement.appendChild(gStatusData[i].createHtml());
54  }
55
56  // Debugging stats.
57  document.getElementById('num-ticks-until-refresh').innerHTML =
58      gTicksUntilRefresh;
59  document.getElementById('num-requests-in-flight').innerHTML =
60      gNumRequestsInFlight;
61  document.getElementById('num-requests-ignored').innerHTML =
62      gNumRequestsIgnored;
63  document.getElementById('num-requests-retried').innerHTML =
64      gNumRequestsRetried;
65}
66
67/**
68 * Organizes all of the bots by category, then alphabetically within their
69 * categories.
70 */
71function sortBotNamesByCategory(botInfo) {
72  // Bucket all of the bots according to their category.
73  var allBotNames = Object.keys(botInfo);
74  var bucketedNames = {};
75  for (var i = 0; i < allBotNames.length; ++i) {
76    var botName = allBotNames[i];
77    var category = botInfo[botName].category;
78
79    if (!bucketedNames[category]) bucketedNames[category] = [];
80    bucketedNames[category].push(botName);
81  }
82
83  // Alphabetically sort bots within their buckets, then append them to the
84  // current list.
85  var sortedBotNames = [];
86  var allCategories = Object.keys(bucketedNames);
87  allCategories.sort();
88  for (var i = 0; i < allCategories.length; ++i) {
89    var category = allCategories[i];
90    var bucketBots = bucketedNames[category];
91    bucketBots.sort();
92
93    for (var j = 0; j < bucketBots.length; ++j) {
94      sortedBotNames.push(bucketBots[j]);
95    }
96  }
97
98  return sortedBotNames;
99}
100
101/** Update all the waterfall data. */
102function updateStatusHTML() {
103  var table = document.getElementById('build-info');
104  while (table.rows.length > 0) {
105    table.deleteRow(-1);
106  }
107
108  for (var i = 0; i < gWaterfallData.length; ++i) {
109    gWaterfallData[i].updateWaterfallStatusHTML();
110  }
111}
112
113/** Marks the waterfall data as dirty due to updated filter. */
114function filterUpdated() {
115  gWaterfallDataIsDirty = true;
116}
117
118/** Update the page content. */
119function updateContent() {
120  if (--gTicksUntilRefresh <= 0) {
121    gTicksUntilRefresh = TICKS_BETWEEN_REFRESHES;
122    queryServersForInfo();
123  }
124
125  // Redraw the page content.
126  if (gWaterfallDataIsDirty) {
127    gWaterfallDataIsDirty = false;
128    updateStatusHTML();
129
130    if (document.getElementById('failure-info')) {
131      updateCorrelationsHTML();
132    }
133  }
134  updateSidebarHTML();
135}
136
137/** Initialize all the things. */
138function initialize() {
139  var gStartTimestamp = new Date().getTime();
140
141  // Initialize the waterfall pages.
142  for (var i = 0; i < kBuilderPages.length; ++i) {
143    gWaterfallData.push(new WaterfallInfo(kBuilderPages[i]));
144  }
145
146  // Initialize the status pages.
147  for (var i = 0; i < kStatusPages.length; ++i) {
148    gStatusData.push(new StatusPageInfo(kStatusPages[i][0],
149                                        kStatusPages[i][1]));
150  }
151
152  // Kick off the main loops.
153  queryServersForInfo();
154  updateStatusHTML();
155  setInterval('updateContent()', 1000);
156}
157