Dashboard code restructuring
[WebKit-https.git] / Tools / BuildSlaveSupport / build.webkit.org-config / public_html / dashboard / Scripts / BubbleQueueView.js
1 /*
2  * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 BubbleQueueView = function(queues)
27 {
28     QueueView.call(this);
29
30     this.queues = queues || [];
31
32     this.queues.forEach(function(queue) {
33         if (this.platform && this.platform != queue.platform)
34             throw "A bubble queue view may not contain queues for multiple platforms."
35         else
36             this.platform = queue.platform;
37         queue.addEventListener(BubbleQueue.Event.Updated, this._queueUpdated, this);
38     }.bind(this));
39
40     this.update();
41 };
42
43 BaseObject.addConstructorFunctions(BubbleQueueView);
44
45 BubbleQueueView.prototype = {
46     constructor: BubbleQueueView,
47     __proto__: QueueView.prototype,
48
49     update: function()
50     {
51         QueueView.prototype.update.call(this);
52
53         this.element.removeChildren();
54
55         function appendQueue(queue)
56         {
57             var queueLabel = document.createElement("a");
58             queueLabel.classList.add("queueLabel");
59             queueLabel.textContent = queue.title;
60             queueLabel.href = queue.statusPageURL;
61             queueLabel.target = "_blank";
62             this.element.appendChild(queueLabel);
63
64             var patchCount = queue.patchCount;
65
66             var message = patchCount === 1 ? "patch in queue" : "patches in queue";
67             var status = new StatusLineView(message, StatusLineView.Status.Neutral, null, patchCount || "0");
68             this.element.appendChild(status.element);
69
70             new PopoverTracker(status.statusBubbleElement, this._presentPopoverForBubbleQueue.bind(this), queue);
71         }
72
73         this.queues.forEach(function(queue) {
74             appendQueue.call(this, queue);
75         }, this);
76     },
77
78     _addQueueHeadingToPopover: function(queue, content)
79     {
80         var title = document.createElement("div");
81         title.className = "popover-queue-heading";
82
83         this.addTextToRow(title, "queue-name", queue.id);
84         this.addLinkToRow(title, "queue-status-link", "status page", queue.statusPageURL);
85         this.addLinkToRow(title, "queue-charts-link", "charts", queue.chartsPageURL);
86
87         content.appendChild(title);
88     },
89
90     _addBotsHeadingToPopover: function(queue, content)
91     {
92         var title = document.createElement("div");
93         title.className = "popover-bots-heading";
94         title.textContent = "latest bot event";
95         content.appendChild(title);
96     },
97
98     _timeIntervalString: function(time)
99     {
100         var secondsInHour = 60 * 60;
101         var timeDifference = (Date.now() - time.getTime()) / 1000;
102         var hours = Math.floor(timeDifference / secondsInHour);
103         var minutes = Math.floor((timeDifference - hours * secondsInHour) / 60);
104         var hoursPart = "";
105         if (hours === 1)
106             hoursPart = "1\xa0hour and ";
107         else if (hours > 0)
108             hoursPart = hours + "\xa0hours and ";
109         if (!minutes)
110             return "less than a minute";
111         if (minutes === 1)
112             return hoursPart + "1\xa0minute";
113         return hoursPart + minutes + "\xa0minutes";
114     },
115
116     _popoverContentForBubbleQueue: function(queue)
117     {
118         var content = document.createElement("div");
119         content.className = "bubble-server-popover";
120
121         this._addQueueHeadingToPopover(queue, content);
122         this._addDividerToPopover(content);
123
124         var patches = queue.patches;
125         for (var i = 0, end = patches.length; i < end; ++i) {
126             var patch = patches[i];
127
128             var rowElement = document.createElement("div");
129
130             this.addLinkToRow(rowElement, "patch-details-link", patch.attachmentID, patch.statusPageURL);
131
132             if (patch.retryCount)
133                 this.addTextToRow(rowElement, "failure-count", patch.retryCount + "\xa0" + (patch.retryCount === 1 ? "attempt" : "attempts"));
134
135             if (patch.detailedResultsURLForLatestMessage)
136                 this.addLinkToRow(rowElement, "latest-status-with-link", patch.latestMessage, patch.detailedResultsURLForLatestMessage);
137             else if (patch.latestMessage && patch.latestMessage.length)
138                 this.addTextToRow(rowElement, "latest-status-no-link", patch.latestMessage);
139             else if (patch.active) {
140                 this.addTextToRow(rowElement, "latest-status-no-link", "Started");
141                 this.addTextToRow(rowElement, "time-since-message", this._timeIntervalString(patch.activeSince) + "\xa0ago");
142             } else
143                 this.addTextToRow(rowElement, "latest-status-no-link", "Not started yet");
144
145             if (patch.latestMessageTime)
146                 this.addTextToRow(rowElement, "time-since-message", this._timeIntervalString(patch.latestMessageTime) + "\xa0ago");
147
148             this.addLinkToRow(rowElement, "bugzilla-link", "bugzilla", bugzilla.detailsURLForAttachment(patch.attachmentID));
149
150             content.appendChild(rowElement);
151         }
152
153         this._addDividerToPopover(content);
154         this._addBotsHeadingToPopover(queue, content);
155         this._addDividerToPopover(content);
156
157         var bots = queue.bots.slice(0).sort(function(a, b) { return (a.id < b.id) ? -1 : 1; });
158         for (var i = 0, end = bots.length; i < end; ++i) {
159             var bot = bots[i];
160
161             var rowElement = document.createElement("div");
162
163             this.addLinkToRow(rowElement, "bot-status-link", bot.id, bot.statusPageURL);
164             this.addTextToRow(rowElement, "bot-status-description", this._timeIntervalString(bot.latestMessageTime) + "\xa0ago");
165
166             content.appendChild(rowElement);
167         }
168
169         return content;
170     },
171
172     _presentPopoverForBubbleQueue: function(element, popover, queue)
173     {
174         if (queue.loadedDetailedStatus)
175             var content = this._popoverContentForBubbleQueue(queue);
176         else {
177             var content = document.createElement("div");
178             content.className = "bubble-server-popover";
179
180             var loadingIndicator = document.createElement("div");
181             loadingIndicator.className = "loading-indicator";
182             loadingIndicator.textContent = "Loading\u2026";
183             content.appendChild(loadingIndicator);
184
185             queue.loadDetailedStatus(function() {
186                 popover.content = this._popoverContentForBubbleQueue(queue);
187             }.bind(this));
188         }
189
190         var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
191         popover.content = content;
192         popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
193         return true;
194     },
195
196     _updateQueues: function()
197     {
198         this.queues.forEach(function(queue) { queue.update(); });
199     },
200
201     _queueUpdated: function(event)
202     {
203         this.updateSoon();
204     },
205 };