blob: d752149c746238406c8da3a7d13a02d8ff662cdf [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 Hesketh4863b602014-03-21 14:19:06 +110020 var $container, $msg, $indicator, $queueInfo, $queueEventsNum,
Joshua Heskethcbdcca12014-03-20 16:06:25 +110021 $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) {
Joshua Hesketh4863b602014-03-21 14:19:06 +110053 $msg.removeClass('alert-danger').addClass('alert-info');
Joshua Hesketh298c4912014-03-20 16:06:25 +110054 $msg.text(data.message);
Joshua Hesketh4863b602014-03-21 14:19:06 +110055 $msg.show();
Joshua Hesketh298c4912014-03-20 16:06:25 +110056 } else {
57 $msg.empty();
Joshua Hesketh4863b602014-03-21 14:19:06 +110058 $msg.hide();
Joshua Hesketh298c4912014-03-20 16:06:25 +110059 }
Timo Tijhof51516cd2013-04-09 01:32:29 +020060
Joshua Hesketh298c4912014-03-20 16:06:25 +110061 if ('zuul_version' in data) {
62 $('#zuul-version-span').text(data['zuul_version']);
63 }
64 if ('last_reconfigured' in data) {
65 var last_reconfigured =
66 new Date(data['last_reconfigured']);
67 $('#last-reconfigured-span').text(
68 last_reconfigured.toString());
69 }
70
71 $pipelines.html('');
72 $.each(data.pipelines, function (i, pipeline) {
73 $pipelines.append(zuul.format.pipeline(pipeline));
74 });
75
76 $queueEventsNum.text(
77 data.trigger_event_queue ?
78 data.trigger_event_queue.length : '0'
79 );
80 $queueResultsNum.text(
81 data.result_event_queue ?
82 data.result_event_queue.length : '0'
83 );
84 })
85 .fail(function (err, jqXHR, errMsg) {
86 $msg.text(source + ': ' + errMsg).show();
Timo Tijhof51516cd2013-04-09 01:32:29 +020087 $msgWrap.removeClass('zuul-msg-wrap-off');
Joshua Hesketh298c4912014-03-20 16:06:25 +110088 })
89 .complete(function () {
90 xhr = undefined;
91 zuul.emit('update-end');
Timo Tijhof51516cd2013-04-09 01:32:29 +020092 });
93
Timo Tijhof51516cd2013-04-09 01:32:29 +020094 return xhr;
95 },
96
97 format: {
98 change: function (change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +110099 if (change.id.length === 40) {
100 change.id = change.id.substr(0, 7);
101 }
Timo Tijhof51516cd2013-04-09 01:32:29 +0200102
Joshua Hesketh298c4912014-03-20 16:06:25 +1100103 var $html = $('<div />')
Joshua Hesketh4863b602014-03-21 14:19:06 +1100104 .addClass('panel panel-default zuul-change')
105
106 var $change_header = $('<div />').text(change.project);
107 $change_header.addClass('panel-heading');
Joshua Hesketh298c4912014-03-20 16:06:25 +1100108
109 if (change.url !== null) {
110 var $id_span = $('<span />').append(
111 $("<a />").attr("href", change.url).text(change.id)
112 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200113 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100114 else {
115 var $id_span = $('<span />').text(change.id);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200116 }
Joshua Hesketh4863b602014-03-21 14:19:06 +1100117 $change_header.append($id_span.addClass('zuul-change-id'));
118 $html.append($change_header);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200119
Joshua Hesketh4863b602014-03-21 14:19:06 +1100120 var $list = $('<ul />');
121 $list.addClass('list-group');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200122 $.each(change.jobs, function (i, job) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100123 var $item = $('<li />');
Joshua Hesketh4863b602014-03-21 14:19:06 +1100124 $item.addClass('list-group-item');
125 $item.addClass('zuul-change-job');
126
127 if (job.url !== null) {
128 $job_line = $('<a href="' + job.url + '" />').
129 addClass('zuul-change-job-link');
130 }
131 else{
132 $job_line = $('<span />').
133 addClass('zuul-change-job-link');
134 }
135 $job_line.text(job.name);
Joshua Hesketh298c4912014-03-20 16:06:25 +1100136
137 var result = job.result ? job.result.toLowerCase() : null;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200138 if (result === null) {
139 result = job.url ? 'in progress' : 'queued';
140 }
141 switch (result) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100142 case 'success':
143 resultClass = ' label-success';
144 break;
145 case 'failure':
Joshua Hesketh4863b602014-03-21 14:19:06 +1100146 resultClass = ' label-danger';
Joshua Hesketh298c4912014-03-20 16:06:25 +1100147 break;
Joshua Hesketh298c4912014-03-20 16:06:25 +1100148 case 'unstable':
149 resultClass = ' label-warning';
150 break;
Joshua Hesketh4863b602014-03-21 14:19:06 +1100151 case 'in progress':
152 case 'queued':
153 case 'lost':
154 resultClass = ' label-default';
155 break;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200156 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100157
Joshua Hesketh4863b602014-03-21 14:19:06 +1100158 $job_line.append(
159 $('<span />').addClass('zuul-result label').
160 addClass(resultClass).text(result)
Joshua Hesketh298c4912014-03-20 16:06:25 +1100161 );
162
Timo Tijhof51516cd2013-04-09 01:32:29 +0200163 if (job.voting === false) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100164 $job_line.append(
165 $(' <span />').addClass('muted').
166 text(' (non-voting)')
167 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200168 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100169 $item.append($job_line);
170 $list.append($item);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200171 });
172
Joshua Hesketh298c4912014-03-20 16:06:25 +1100173 $html.append($list);
174 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200175 },
176
177 pipeline: function (pipeline) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100178 var $html = $('<div />')
Joshua Hesketh4863b602014-03-21 14:19:06 +1100179 .addClass('zuul-pipeline col-md-4')
Joshua Hesketh298c4912014-03-20 16:06:25 +1100180 .append($('<h3 />').text(pipeline.name));
181
Timo Tijhof51516cd2013-04-09 01:32:29 +0200182 if (typeof pipeline.description === 'string') {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100183 $html.append(
184 $('<p />').append(
185 $('<small />').text(pipeline.description)
186 )
187 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200188 }
189
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100190 $.each(pipeline.change_queues,
191 function (queueNum, changeQueue) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200192 $.each(changeQueue.heads, function (headNum, changes) {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100193 if (pipeline.change_queues.length > 1 &&
194 headNum === 0) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200195 var name = changeQueue.name;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200196 if (name.length > 32) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100197 short_name = name.substr(0, 32) + '...';
Timo Tijhof51516cd2013-04-09 01:32:29 +0200198 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100199 $html.append(
200 $('<p />')
201 .text('Queue: ')
202 .append(
203 $('<abbr />')
204 .attr('title', name)
205 .text(short_name)
206 )
207 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200208 }
209 $.each(changes, function (changeNum, change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100210 $html.append(zuul.format.change(change))
Timo Tijhof51516cd2013-04-09 01:32:29 +0200211 });
212 });
213 });
Joshua Hesketh298c4912014-03-20 16:06:25 +1100214 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200215 }
216 },
217
218 emit: function () {
219 $jq.trigger.apply($jq, arguments);
220 return this;
221 },
222 on: function () {
223 $jq.on.apply($jq, arguments);
224 return this;
225 },
226 one: function () {
227 $jq.one.apply($jq, arguments);
228 return this;
229 }
230 };
231
232 $jq = $(zuul);
233
234 $jq.on('update-start', function () {
235 $container.addClass('zuul-container-loading');
236 $indicator.addClass('zuul-spinner-on');
237 });
238
239 $jq.on('update-end', function () {
240 $container.removeClass('zuul-container-loading');
241 setTimeout(function () {
242 $indicator.removeClass('zuul-spinner-on');
243 }, 550);
244 });
245
246 $jq.one('update-end', function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100247 // Do this asynchronous so that if the first update adds a message, it
248 // will not animate while we fade in the content. Instead it simply
249 // appears with the rest of the content.
Timo Tijhof51516cd2013-04-09 01:32:29 +0200250 setTimeout(function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100251 // Fade in the content
252 $container.addClass('zuul-container-ready');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200253 });
254 });
255
256 $(function ($) {
Joshua Hesketh4863b602014-03-21 14:19:06 +1100257 $msg = $('<div />').addClass('alert').hide();
258 $indicator = $('<button class="btn pull-right zuul-spinner">updating '
259 + '<span class="glyphicon glyphicon-refresh"></span>'
260 + '</button>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100261 $queueInfo = $('<p>Queue lengths: <span>0</span> events, ' +
262 '<span>0</span> results.</p>');
Joshua Hesketh298c4912014-03-20 16:06:25 +1100263 $queueEventsNum = $queueInfo.find('span').eq(0);
264 $queueResultsNum = $queueEventsNum.next();
Timo Tijhof51516cd2013-04-09 01:32:29 +0200265 $pipelines = $('<div class="row"></div>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100266 $zuulVersion = $('<p>Zuul version: <span id="zuul-version-span">' +
267 '</span></p>');
268 $lastReconf = $('<p>Last reconfigured: ' +
269 '<span id="last-reconfigured-span"></span></p>');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200270
Joshua Hesketh4863b602014-03-21 14:19:06 +1100271 $container = $('#zuul-container').append($msg, $indicator,
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100272 $queueInfo, $pipelines,
273 $zuulVersion, $lastReconf);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200274
275 zuul.schedule();
276
277 $(document).on({
278 'show.visibility': function () {
279 zuul.enabled = true;
280 zuul.update();
281 },
282 'hide.visibility': function () {
283 zuul.enabled = false;
284 }
285 });
286 });
287}(jQuery));