blob: 0780346063f34559957c9467343eff9e07b75082 [file] [log] [blame]
Timo Tijhof51516cd2013-04-09 01:32:29 +02001// Client script for Zuul status page
2//
3// Copyright 2012 OpenStack Foundation
4// Copyright 2013 Timo Tijhof
5// Copyright 2013 Wikimedia Foundation
6//
7// Licensed under the Apache License, Version 2.0 (the "License"); you may
8// not use this file except in compliance with the License. You may obtain
9// a copy of the License at
10//
11// http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16// License for the specific language governing permissions and limitations
17// under the License.
18
19(function ($) {
Joshua Heskethcbdcca12014-03-20 16:06:25 +110020 var $container, $msg, $msgWrap, $indicator, $queueInfo, $queueEventsNum,
21 $queueResultsNum, $pipelines, $jq;
Joshua Hesketh298c4912014-03-20 16:06:25 +110022 var xhr, zuul,
Timo Tijhof51516cd2013-04-09 01:32:29 +020023 demo = location.search.match(/[?&]demo=([^?&]*)/),
24 source = demo ?
25 './status-' + (demo[1] || 'basic') + '.json-sample' :
James E. Blair7c7ed7a2013-05-15 13:13:26 -070026 'status.json';
Timo Tijhof51516cd2013-04-09 01:32:29 +020027
28 zuul = {
29 enabled: true,
30
31 schedule: function () {
32 if (!zuul.enabled) {
33 setTimeout(zuul.schedule, 5000);
34 return;
35 }
36 zuul.update().complete(function () {
37 setTimeout(zuul.schedule, 5000);
38 });
39 },
40
41 /** @return {jQuery.Promise} */
42 update: function () {
43 // Cancel the previous update if it hasn't completed yet.
44 if (xhr) {
45 xhr.abort();
46 }
47
48 zuul.emit('update-start');
49
Joshua Hesketh298c4912014-03-20 16:06:25 +110050 xhr = $.getJSON(source)
51 .done(function (data) {
52 if ('message' in data) {
53 $msg.text(data.message);
54 $msgWrap.removeClass('zuul-msg-wrap-off');
55 } else {
56 $msg.empty();
57 $msgWrap.addClass('zuul-msg-wrap-off');
58 }
Timo Tijhof51516cd2013-04-09 01:32:29 +020059
Joshua Hesketh298c4912014-03-20 16:06:25 +110060 if ('zuul_version' in data) {
61 $('#zuul-version-span').text(data['zuul_version']);
62 }
63 if ('last_reconfigured' in data) {
64 var last_reconfigured =
65 new Date(data['last_reconfigured']);
66 $('#last-reconfigured-span').text(
67 last_reconfigured.toString());
68 }
69
70 $pipelines.html('');
71 $.each(data.pipelines, function (i, pipeline) {
72 $pipelines.append(zuul.format.pipeline(pipeline));
73 });
74
75 $queueEventsNum.text(
76 data.trigger_event_queue ?
77 data.trigger_event_queue.length : '0'
78 );
79 $queueResultsNum.text(
80 data.result_event_queue ?
81 data.result_event_queue.length : '0'
82 );
83 })
84 .fail(function (err, jqXHR, errMsg) {
85 $msg.text(source + ': ' + errMsg).show();
Timo Tijhof51516cd2013-04-09 01:32:29 +020086 $msgWrap.removeClass('zuul-msg-wrap-off');
Joshua Hesketh298c4912014-03-20 16:06:25 +110087 })
88 .complete(function () {
89 xhr = undefined;
90 zuul.emit('update-end');
Timo Tijhof51516cd2013-04-09 01:32:29 +020091 });
92
Timo Tijhof51516cd2013-04-09 01:32:29 +020093 return xhr;
94 },
95
96 format: {
97 change: function (change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +110098 if (change.id.length === 40) {
99 change.id = change.id.substr(0, 7);
100 }
Timo Tijhof51516cd2013-04-09 01:32:29 +0200101
Joshua Hesketh298c4912014-03-20 16:06:25 +1100102 var $html = $('<div />')
103 .addClass('well well-small zuul-change')
104 var $list = $('<ul />').addClass('nav nav-list');
105 var $first_item = $('<li />').text(change.project)
106 .addClass('nav-header');
107
108 if (change.url !== null) {
109 var $id_span = $('<span />').append(
110 $("<a />").attr("href", change.url).text(change.id)
111 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200112 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100113 else {
114 var $id_span = $('<span />').text(change.id);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200115 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100116 $first_item.append($id_span.addClass('zuul-change-id'));
117 $list.append($first_item);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200118
119 $.each(change.jobs, function (i, job) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100120 var $item = $('<li />');
121
122 var result = job.result ? job.result.toLowerCase() : null;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200123 if (result === null) {
124 result = job.url ? 'in progress' : 'queued';
125 }
126 switch (result) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100127 case 'success':
128 resultClass = ' label-success';
129 break;
130 case 'failure':
131 resultClass = ' label-important';
132 break;
133 case 'lost':
134 case 'unstable':
135 resultClass = ' label-warning';
136 break;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200137 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100138
139 $item.addClass('zuul-change-job');
140 if (job.url !== null) {
141 $job_line = $('<a href="' + job.url + '" />').
142 addClass('zuul-change-job-link');
143 }
144 else{
145 $job_line = $('<span />').
146 addClass('zuul-change-job-link');
147 }
148 $job_line.text(job.name)
149 .append(
150 $('<span />').addClass('zuul-result label').
151 addClass(resultClass).text(result)
152 );
153
Timo Tijhof51516cd2013-04-09 01:32:29 +0200154 if (job.voting === false) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100155 $job_line.append(
156 $(' <span />').addClass('muted').
157 text(' (non-voting)')
158 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200159 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100160 $item.append($job_line);
161 $list.append($item);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200162 });
163
Joshua Hesketh298c4912014-03-20 16:06:25 +1100164 $html.append($list);
165 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200166 },
167
168 pipeline: function (pipeline) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100169 var $html = $('<div />')
170 .addClass('zuul-pipeline span4')
171 .append($('<h3 />').text(pipeline.name));
172
Timo Tijhof51516cd2013-04-09 01:32:29 +0200173 if (typeof pipeline.description === 'string') {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100174 $html.append(
175 $('<p />').append(
176 $('<small />').text(pipeline.description)
177 )
178 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200179 }
180
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100181 $.each(pipeline.change_queues,
182 function (queueNum, changeQueue) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200183 $.each(changeQueue.heads, function (headNum, changes) {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100184 if (pipeline.change_queues.length > 1 &&
185 headNum === 0) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200186 var name = changeQueue.name;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200187 if (name.length > 32) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100188 short_name = name.substr(0, 32) + '...';
Timo Tijhof51516cd2013-04-09 01:32:29 +0200189 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100190 $html.append(
191 $('<p />')
192 .text('Queue: ')
193 .append(
194 $('<abbr />')
195 .attr('title', name)
196 .text(short_name)
197 )
198 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200199 }
200 $.each(changes, function (changeNum, change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100201 $html.append(zuul.format.change(change))
Timo Tijhof51516cd2013-04-09 01:32:29 +0200202 });
203 });
204 });
Joshua Hesketh298c4912014-03-20 16:06:25 +1100205 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200206 }
207 },
208
209 emit: function () {
210 $jq.trigger.apply($jq, arguments);
211 return this;
212 },
213 on: function () {
214 $jq.on.apply($jq, arguments);
215 return this;
216 },
217 one: function () {
218 $jq.one.apply($jq, arguments);
219 return this;
220 }
221 };
222
223 $jq = $(zuul);
224
225 $jq.on('update-start', function () {
226 $container.addClass('zuul-container-loading');
227 $indicator.addClass('zuul-spinner-on');
228 });
229
230 $jq.on('update-end', function () {
231 $container.removeClass('zuul-container-loading');
232 setTimeout(function () {
233 $indicator.removeClass('zuul-spinner-on');
234 }, 550);
235 });
236
237 $jq.one('update-end', function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100238 // Do this asynchronous so that if the first update adds a message, it
239 // will not animate while we fade in the content. Instead it simply
240 // appears with the rest of the content.
Timo Tijhof51516cd2013-04-09 01:32:29 +0200241 setTimeout(function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100242 // Fade in the content
243 $container.addClass('zuul-container-ready');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200244 });
245 });
246
247 $(function ($) {
248 $msg = $('<div class="zuul-msg alert alert-error"></div>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100249 $msgWrap = $msg.wrap('<div class="zuul-msg-wrap zuul-msg-wrap-off">' +
250 '</div>').parent();
251 $indicator = $('<span class="btn pull-right zuul-spinner">updating ' +
252 '<i class="icon-refresh"></i></span>');
253 $queueInfo = $('<p>Queue lengths: <span>0</span> events, ' +
254 '<span>0</span> results.</p>');
Joshua Hesketh298c4912014-03-20 16:06:25 +1100255 $queueEventsNum = $queueInfo.find('span').eq(0);
256 $queueResultsNum = $queueEventsNum.next();
Timo Tijhof51516cd2013-04-09 01:32:29 +0200257 $pipelines = $('<div class="row"></div>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100258 $zuulVersion = $('<p>Zuul version: <span id="zuul-version-span">' +
259 '</span></p>');
260 $lastReconf = $('<p>Last reconfigured: ' +
261 '<span id="last-reconfigured-span"></span></p>');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200262
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100263 $container = $('#zuul-container').append($msgWrap, $indicator,
264 $queueInfo, $pipelines,
265 $zuulVersion, $lastReconf);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200266
267 zuul.schedule();
268
269 $(document).on({
270 'show.visibility': function () {
271 zuul.enabled = true;
272 zuul.update();
273 },
274 'hide.visibility': function () {
275 zuul.enabled = false;
276 }
277 });
278 });
279}(jQuery));