blob: 16195e8e313a63e5b59d275127fc90a1138f10d1 [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=([^?&]*)/),
Joshua Hesketh668700b2014-03-21 14:25:53 +110024 source_url = location.search.match(/[?&]source_url=([^?&]*)/),
Timo Tijhof51516cd2013-04-09 01:32:29 +020025 source = demo ?
26 './status-' + (demo[1] || 'basic') + '.json-sample' :
James E. Blair7c7ed7a2013-05-15 13:13:26 -070027 'status.json';
Joshua Hesketh668700b2014-03-21 14:25:53 +110028 source = source_url ? source_url[1] : source;
Timo Tijhof51516cd2013-04-09 01:32:29 +020029
30 zuul = {
31 enabled: true,
32
33 schedule: function () {
34 if (!zuul.enabled) {
35 setTimeout(zuul.schedule, 5000);
36 return;
37 }
38 zuul.update().complete(function () {
39 setTimeout(zuul.schedule, 5000);
40 });
41 },
42
43 /** @return {jQuery.Promise} */
44 update: function () {
45 // Cancel the previous update if it hasn't completed yet.
46 if (xhr) {
47 xhr.abort();
48 }
49
50 zuul.emit('update-start');
51
Joshua Hesketh298c4912014-03-20 16:06:25 +110052 xhr = $.getJSON(source)
53 .done(function (data) {
54 if ('message' in data) {
Joshua Hesketh4863b602014-03-21 14:19:06 +110055 $msg.removeClass('alert-danger').addClass('alert-info');
Joshua Hesketh298c4912014-03-20 16:06:25 +110056 $msg.text(data.message);
Joshua Hesketh4863b602014-03-21 14:19:06 +110057 $msg.show();
Joshua Hesketh298c4912014-03-20 16:06:25 +110058 } else {
59 $msg.empty();
Joshua Hesketh4863b602014-03-21 14:19:06 +110060 $msg.hide();
Joshua Hesketh298c4912014-03-20 16:06:25 +110061 }
Timo Tijhof51516cd2013-04-09 01:32:29 +020062
Joshua Hesketh298c4912014-03-20 16:06:25 +110063 if ('zuul_version' in data) {
64 $('#zuul-version-span').text(data['zuul_version']);
65 }
66 if ('last_reconfigured' in data) {
67 var last_reconfigured =
68 new Date(data['last_reconfigured']);
69 $('#last-reconfigured-span').text(
70 last_reconfigured.toString());
71 }
72
73 $pipelines.html('');
74 $.each(data.pipelines, function (i, pipeline) {
75 $pipelines.append(zuul.format.pipeline(pipeline));
76 });
77
78 $queueEventsNum.text(
79 data.trigger_event_queue ?
80 data.trigger_event_queue.length : '0'
81 );
82 $queueResultsNum.text(
83 data.result_event_queue ?
84 data.result_event_queue.length : '0'
85 );
86 })
87 .fail(function (err, jqXHR, errMsg) {
88 $msg.text(source + ': ' + errMsg).show();
Timo Tijhof51516cd2013-04-09 01:32:29 +020089 $msgWrap.removeClass('zuul-msg-wrap-off');
Joshua Hesketh298c4912014-03-20 16:06:25 +110090 })
91 .complete(function () {
92 xhr = undefined;
93 zuul.emit('update-end');
Timo Tijhof51516cd2013-04-09 01:32:29 +020094 });
95
Timo Tijhof51516cd2013-04-09 01:32:29 +020096 return xhr;
97 },
98
99 format: {
100 change: function (change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100101 if (change.id.length === 40) {
102 change.id = change.id.substr(0, 7);
103 }
Timo Tijhof51516cd2013-04-09 01:32:29 +0200104
Joshua Hesketh298c4912014-03-20 16:06:25 +1100105 var $html = $('<div />')
Joshua Hesketh4863b602014-03-21 14:19:06 +1100106 .addClass('panel panel-default zuul-change')
107
108 var $change_header = $('<div />').text(change.project);
109 $change_header.addClass('panel-heading');
Joshua Hesketh298c4912014-03-20 16:06:25 +1100110
111 if (change.url !== null) {
112 var $id_span = $('<span />').append(
113 $("<a />").attr("href", change.url).text(change.id)
114 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200115 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100116 else {
117 var $id_span = $('<span />').text(change.id);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200118 }
Joshua Hesketh4863b602014-03-21 14:19:06 +1100119 $change_header.append($id_span.addClass('zuul-change-id'));
120 $html.append($change_header);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200121
Joshua Hesketh4863b602014-03-21 14:19:06 +1100122 var $list = $('<ul />');
123 $list.addClass('list-group');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200124 $.each(change.jobs, function (i, job) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100125 var $item = $('<li />');
Joshua Hesketh4863b602014-03-21 14:19:06 +1100126 $item.addClass('list-group-item');
127 $item.addClass('zuul-change-job');
128
129 if (job.url !== null) {
130 $job_line = $('<a href="' + job.url + '" />').
131 addClass('zuul-change-job-link');
132 }
133 else{
134 $job_line = $('<span />').
135 addClass('zuul-change-job-link');
136 }
137 $job_line.text(job.name);
Joshua Hesketh298c4912014-03-20 16:06:25 +1100138
139 var result = job.result ? job.result.toLowerCase() : null;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200140 if (result === null) {
141 result = job.url ? 'in progress' : 'queued';
142 }
143 switch (result) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100144 case 'success':
145 resultClass = ' label-success';
146 break;
147 case 'failure':
Joshua Hesketh4863b602014-03-21 14:19:06 +1100148 resultClass = ' label-danger';
Joshua Hesketh298c4912014-03-20 16:06:25 +1100149 break;
Joshua Hesketh298c4912014-03-20 16:06:25 +1100150 case 'unstable':
151 resultClass = ' label-warning';
152 break;
Joshua Hesketh4863b602014-03-21 14:19:06 +1100153 case 'in progress':
154 case 'queued':
155 case 'lost':
156 resultClass = ' label-default';
157 break;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200158 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100159
Joshua Hesketh4863b602014-03-21 14:19:06 +1100160 $job_line.append(
161 $('<span />').addClass('zuul-result label').
162 addClass(resultClass).text(result)
Joshua Hesketh298c4912014-03-20 16:06:25 +1100163 );
164
Timo Tijhof51516cd2013-04-09 01:32:29 +0200165 if (job.voting === false) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100166 $job_line.append(
167 $(' <span />').addClass('muted').
168 text(' (non-voting)')
169 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200170 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100171 $item.append($job_line);
172 $list.append($item);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200173 });
174
Joshua Hesketh298c4912014-03-20 16:06:25 +1100175 $html.append($list);
176 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200177 },
178
179 pipeline: function (pipeline) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100180 var $html = $('<div />')
Joshua Hesketh4863b602014-03-21 14:19:06 +1100181 .addClass('zuul-pipeline col-md-4')
Joshua Hesketh298c4912014-03-20 16:06:25 +1100182 .append($('<h3 />').text(pipeline.name));
183
Timo Tijhof51516cd2013-04-09 01:32:29 +0200184 if (typeof pipeline.description === 'string') {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100185 $html.append(
186 $('<p />').append(
187 $('<small />').text(pipeline.description)
188 )
189 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200190 }
191
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100192 $.each(pipeline.change_queues,
193 function (queueNum, changeQueue) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200194 $.each(changeQueue.heads, function (headNum, changes) {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100195 if (pipeline.change_queues.length > 1 &&
196 headNum === 0) {
Timo Tijhof51516cd2013-04-09 01:32:29 +0200197 var name = changeQueue.name;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200198 if (name.length > 32) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100199 short_name = name.substr(0, 32) + '...';
Timo Tijhof51516cd2013-04-09 01:32:29 +0200200 }
Joshua Hesketh298c4912014-03-20 16:06:25 +1100201 $html.append(
202 $('<p />')
203 .text('Queue: ')
204 .append(
205 $('<abbr />')
206 .attr('title', name)
207 .text(short_name)
208 )
209 );
Timo Tijhof51516cd2013-04-09 01:32:29 +0200210 }
211 $.each(changes, function (changeNum, change) {
Joshua Hesketh298c4912014-03-20 16:06:25 +1100212 $html.append(zuul.format.change(change))
Timo Tijhof51516cd2013-04-09 01:32:29 +0200213 });
214 });
215 });
Joshua Hesketh298c4912014-03-20 16:06:25 +1100216 return $html;
Timo Tijhof51516cd2013-04-09 01:32:29 +0200217 }
218 },
219
220 emit: function () {
221 $jq.trigger.apply($jq, arguments);
222 return this;
223 },
224 on: function () {
225 $jq.on.apply($jq, arguments);
226 return this;
227 },
228 one: function () {
229 $jq.one.apply($jq, arguments);
230 return this;
231 }
232 };
233
234 $jq = $(zuul);
235
236 $jq.on('update-start', function () {
237 $container.addClass('zuul-container-loading');
238 $indicator.addClass('zuul-spinner-on');
239 });
240
241 $jq.on('update-end', function () {
242 $container.removeClass('zuul-container-loading');
243 setTimeout(function () {
244 $indicator.removeClass('zuul-spinner-on');
245 }, 550);
246 });
247
248 $jq.one('update-end', function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100249 // Do this asynchronous so that if the first update adds a message, it
250 // will not animate while we fade in the content. Instead it simply
251 // appears with the rest of the content.
Timo Tijhof51516cd2013-04-09 01:32:29 +0200252 setTimeout(function () {
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100253 // Fade in the content
254 $container.addClass('zuul-container-ready');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200255 });
256 });
257
258 $(function ($) {
Joshua Hesketh4863b602014-03-21 14:19:06 +1100259 $msg = $('<div />').addClass('alert').hide();
260 $indicator = $('<button class="btn pull-right zuul-spinner">updating '
261 + '<span class="glyphicon glyphicon-refresh"></span>'
262 + '</button>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100263 $queueInfo = $('<p>Queue lengths: <span>0</span> events, ' +
264 '<span>0</span> results.</p>');
Joshua Hesketh298c4912014-03-20 16:06:25 +1100265 $queueEventsNum = $queueInfo.find('span').eq(0);
266 $queueResultsNum = $queueEventsNum.next();
Timo Tijhof51516cd2013-04-09 01:32:29 +0200267 $pipelines = $('<div class="row"></div>');
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100268 $zuulVersion = $('<p>Zuul version: <span id="zuul-version-span">' +
269 '</span></p>');
270 $lastReconf = $('<p>Last reconfigured: ' +
271 '<span id="last-reconfigured-span"></span></p>');
Timo Tijhof51516cd2013-04-09 01:32:29 +0200272
Joshua Hesketh4863b602014-03-21 14:19:06 +1100273 $container = $('#zuul-container').append($msg, $indicator,
Joshua Heskethcbdcca12014-03-20 16:06:25 +1100274 $queueInfo, $pipelines,
275 $zuulVersion, $lastReconf);
Timo Tijhof51516cd2013-04-09 01:32:29 +0200276
277 zuul.schedule();
278
279 $(document).on({
280 'show.visibility': function () {
281 zuul.enabled = true;
282 zuul.update();
283 },
284 'hide.visibility': function () {
285 zuul.enabled = false;
286 }
287 });
288 });
289}(jQuery));