Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: appengine/swarming/elements/res/imp/botpage/bot-page.html

Issue 2291323002: Introduce new bot-page UI (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@bot-page
Patch Set: Fix some query glitches Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 <!-- 1 <!--
2 Copyright 2016 The LUCI Authors. All rights reserved. 2 Copyright 2016 The LUCI Authors. All rights reserved.
3 Use of this source code is governed under the Apache License, Version 2.0 3 Use of this source code is governed under the Apache License, Version 2.0
4 that can be found in the LICENSE file. 4 that can be found in the LICENSE file.
5 5
6 This in an HTML Import-able file that contains the definition 6 This in an HTML Import-able file that contains the definition
7 of the following elements: 7 of the following elements:
8 8
9 <bot-page> 9 <bot-page>
10 10
11 bot-page shows the tasks, events, and dimensions of a bot. 11 bot-page shows the tasks, events, and dimensions of a bot.
12 12
13 This is a top-level element. 13 This is a top-level element.
14 14
15 Properties: 15 Properties:
16 bot_id: String, Used in testing to specify a bot_id 16 bot_id: String, Used in testing to specify a bot_id
17 client_id: String, Oauth 2.0 client id. It will be set by server-side 17 client_id: String, Oauth 2.0 client id. It will be set by server-side
18 template evaluation. 18 template evaluation.
19 19
20 Methods: 20 Methods:
21 None. 21 None.
22 22
23 Events: 23 Events:
24 None. 24 None.
25 --> 25 -->
26 26
27 <link rel="import" href="/res/imp/bower_components/iron-collapse/iron-collapse.h tml">
28 <link rel="import" href="/res/imp/bower_components/iron-icon/iron-icon.html">
29 <link rel="import" href="/res/imp/bower_components/iron-icons/iron-icons.html">
30 <link rel="import" href="/res/imp/bower_components/paper-button/paper-button.htm l">
31 <link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox .html">
32 <link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html" >
33 <link rel="import" href="/res/imp/bower_components/paper-tabs/paper-tabs.html">
34 <link rel="import" href="/res/imp/bower_components/paper-icon-button/paper-icon- button.html">
27 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> 35 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html">
28 36
29 <link rel="import" href="/res/imp/common/common-behavior.html">
30 <link rel="import" href="/res/imp/common/swarming-app.html"> 37 <link rel="import" href="/res/imp/common/swarming-app.html">
31 <link rel="import" href="/res/imp/common/url-param.html"> 38 <link rel="import" href="/res/imp/common/url-param.html">
32 39
33 <link rel="import" href="bot-page-data.html"> 40 <link rel="import" href="bot-page-data.html">
41 <link rel="import" href="bot-page-shared-behavior.html">
34 42
35 43
36 <dom-module id="bot-page"> 44 <dom-module id="bot-page">
37 <template> 45 <template>
38 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style"> 46 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style">
39 47
48 .header {
49 max-width: 450px;
50 }
51
52 .title {
53 font-size: 1.5em;
54 font-weight: bold;
55 margin-bottom: 5px;
56 }
57 .id_input {
58 --paper-input-container-input: {
59 font-size: 2em;
60 };
61 }
62 .refresh {
63 max-width: 65px;
64 max-height: 65px;
65 width: initial;
66 height: initial;
67 margin: 6px;
68 }
69
70 table {
71 border-collapse: collapse;
72 margin-left: 5px;
73 margin-bottom: 5px;
74 }
75 td, th {
76 border: 1px solid #BBB;
77 padding: 5px;
78 }
79
80 .quarantined, .failed_task {
81 background-color: #ffdddd;
82 }
83 .dead {
84 background-color: #cccccc;
85 }
86
87 .message {
88 white-space: pre-line;
89 font-family: monospace;
90 }
91
92 .bot_state {
93 white-space: pre;
94 font-family: monospace;
95 margin-bottom: 10px;
96 }
97
98 .show_all {
99 margin-bottom: 5px;
100 }
101
102 paper-tabs {
103 background-color: #1F78B4;
104 color: #fff;
105 max-width: 600px;
106 margin-bottom: 5px;
107 }
108 paper-tab.iron-selected {
109 background-color: #A6CEE3;
110 border: 2px solid #1F78B4;
111 color: #fff;
112 font-weight: bold;
113 text-decoration: underline;
114 }
115
40 </style> 116 </style>
41 117
42 <url-param name="id" 118 <url-param name="id"
43 value="{{bot_id}}"> 119 value="{{bot_id}}">
44 </url-param> 120 </url-param>
121 <url-param name="show_all_events"
122 value="{{_show_all}}">
123 </url-param>
124 <url-param name="selected"
125 value="{{_selected}}">
126 </url-param>
127 <url-param name="show_state"
128 value="{{_show_state}}">
129 </url-param>
45 130
46 <swarming-app 131 <swarming-app
47 client_id="[[client_id]]" 132 client_id="[[client_id]]"
48 auth_headers="{{_auth_headers}}" 133 auth_headers="{{_auth_headers}}"
134 permissions="{{_permissions}}"
49 signed_in="{{_signed_in}}" 135 signed_in="{{_signed_in}}"
50 136
51 busy="[[_busy]]" 137 busy="[[_busy]]"
52 name="Swarming Bot Page"> 138 name="Swarming Bot Page">
53 139
54 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 140 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
55 141
56 <div hidden$="[[_not(_signed_in)]]"> 142 <div hidden$="[[_not(_signed_in)]]">
57 143
58 <bot-page-data 144 <bot-page-data
59 auth_headers="[[_auth_headers]]" 145 auth_headers="[[_auth_headers]]"
60 bot_id="[[bot_id]]" 146 bot_id="[[bot_id]]"
61 147
62 bot="{{_bot}}" 148 bot="{{_bot}}"
63 busy="{{_busy}}" 149 busy="{{_busy}}"
64 events="{{_events}}" 150 events="{{_events}}"
65 tasks="{{_tasks}}"> 151 tasks="{{_tasks}}">
66 </bot-page-data> 152 </bot-page-data>
67 153
68 <h1> Bot Page Stub </h1> 154 <div class="header horizontal layout">
155 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input>
156 <paper-icon-button class="refresh" icon="icons:refresh"></paper-icon-b utton>
157 </div>
158
159 <div>
160 <table>
161 <tr class$="[[_isDead(_bot)]]">
162 <td>Last Seen</td>
163 <td title="[[_bot.human_last_seen_ts]]">
164 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td>
165 <td>
166 <!-- dom-ifs are slightly less performant than hidden$=, but
167 prevent things from first drawing and then hiding. We prefer to
168 not flash buttons or quarantined messages -->
169 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]">
170 <paper-button
171 raised>
172 Shut Down Gracefully
173 </paper-button>
174 </template>
175 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]">
176 <paper-button
177 raised>
178 Delete Bot
179 </paper-button>
180 </template>
181 </td>
182 </tr>
183 <template is="dom-if" if="[[_bot.quarantined]]">
184 <tr class="quarantined">
185 <td>Quarantined</td>
186 <td colspan="2">[[_quarantineMessage(_bot)]]</td>
187 </tr>
188 </template>
189 <tr>
190 <td>Current Task</td>
191 <td>
192 <a target="_blank" href$="[[_taskLink(_bot.task_id)]]">
193 [[_task(_bot)]]
194 </a>
195 </td>
196 <td>
197 <!-- TODO(kjlubick) add the cancel button when swarming can
198 cancel running tasks -->
199 </td>
200 </tr>
201 <tr>
202 <td rowspan$="[[_numRows(_bot.dimensions)]]">Dimensions</td>
203 </tr>
204 <template
205 is="dom-repeat"
206 items="[[_bot.dimensions]]"
207 as="dim">
208 <tr>
209 <td>[[dim.key]]</td>
210 <td>[[_concat(dim.value)]]</td>
211 </tr>
212 </template>
213
214 <tr>
215 <td>External IP</td>
216 <td>[[_bot.external_ip]]</td>
217 <td></td>
218 </tr>
219 <tr>
220 <td>Swarming Revision</td>
221 <td>
222 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_shorte n(_bot.version,'8')]]</a>
223 </td>
224 <td></td>
225 </tr>
226 <tr>
227 <td>First seen</td>
228 <td title="[[_bot.human_first_seen_ts]]">
229 [[_timeDiffApprox(_bot.first_seen_ts)]] ago
230 </td>
231 <td></td>
232 </tr>
233 <tr>
234 <td>Authenticated as</td>
235 <td>[[_bot.authenticated_as]]</td>
236 <td></td>
237 </tr>
238 </table>
239
240 <span class="title">State</span>
241 <paper-icon-button
242 hidden="[[_show_state]]"
243 icon="icons:add-circle-outline"
244 on-tap="_toggleState">
245 </paper-icon-button>
246 <paper-icon-button
247 hidden="[[_not(_show_state)]]"
248 icon="icons:remove-circle-outline"
249 on-tap="_toggleState">
250 </paper-icon-button>
251
252 <iron-collapse id="collapse" opened="[[_show_state]]">
253 <div class="bot_state">[[_prettyPrint(_bot.state)]]</div>
254 </iron-collapse>
255 </div>
256
257 <paper-tabs selected="{{_selected}}" no-bar>
258 <paper-tab>Tasks</paper-tab>
259 <paper-tab>Events</paper-tab>
260 </paper-tabs>
261
262 <template is="dom-if" if="[[_not(_selected)]]">
263 <table>
264 <thead>
265 <tr>
266 <th>Task</th>
267 <th>Started</th>
268 <th>Duration</th>
269 <th>Result</th>
270 </tr>
271 </thead>
272 <tbody>
273 <template is="dom-repeat" items="{{_tasks}}" as="task">
274 <tr>
275 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td>
276 <td>[[task.human_started_ts]]</td>
277 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td>
278 <td>[[task.state]]</td>
279 </tr>
280 </template>
281 </tbody>
282 </table>
283 </template>
284
285 <template is="dom-if" if="[[_selected]]">
286 <div class="tab_content">
287 <paper-checkbox class="show_all" checked="{{_show_all}}">
288 Show all events
289 </paper-checkbox>
290 <table class="events_table">
291 <thead>
292 <tr>
293 <th>Message</th>
294 <th>Type</th>
295 <th>Timestamp</th>
296 <th>Task ID</th>
297 <th>Version</th>
298 </tr>
299 </thead>
300 <tbody>
301 <template is="dom-repeat" items="{{_eventList(_events,_show_all) }}" as="event">
302 <tr>
303 <td class="message">[[event.message]]</a></td>
304 <td>[[event.event_type]]</td>
305 <td>[[event.human_ts]]</td>
306 <td><a target="_blank" href$="[[_taskLink(event.task_id)]]"> [[event.task_id]]</a></td>
307 <td>
308 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_ shorten(_bot.version,'8')]]</a>
309 </td>
310 </tr>
311 </template>
312 </tbody>
313 </table>
314 </div>
315 </template>
316 </div>
69 </div> 317 </div>
70 318
71 </swarming-app> 319 </swarming-app>
72 320
73 </template> 321 </template>
74 <script> 322 <script>
75 (function(){ 323 (function(){
76 324
77 325
78 Polymer({ 326 Polymer({
79 is: 'bot-page', 327 is: 'bot-page',
80 328
81 behaviors: [ 329 behaviors: [
82 SwarmingBehaviors.CommonBehavior, 330 SwarmingBehaviors.BotPageBehavior,
83 ], 331 ],
84 332
85 properties: { 333 properties: {
86 bot_id: { 334 bot_id: {
87 type: String, 335 type: String,
88 }, 336 },
89 client_id: { 337 client_id: {
90 type: String, 338 type: String,
91 }, 339 },
92 340
341 // private
stephana 2016/09/01 15:16:18 nit: not necessary.
kjlubick 2016/09/01 17:24:08 Removed.
342 _bot: {
343 type: Object,
344 },
345 _selected: {
346 type: Number,
347 },
348 _show_all: {
349 type: Boolean,
350 },
351 _show_state: {
352 type: Boolean,
353 }
93 }, 354 },
94 355
356 _canCancel: function(bot, permissions) {
357 return bot && bot.task_id && permissions.cancel_task;
358 },
359
360 _canDelete: function(bot, permissions) {
361 return bot && bot.is_dead && permissions.delete_bot;
362 },
363
364 _canShutdown: function(bot, permissions){
365 return bot && !bot.is_dead && permissions.terminate_bot;
366 },
367
368 _concat: function(arr) {
369 if (!arr) {
370 return "";
371 }
372 return arr.join(" | ");
373 },
374
375 _eventList(events, showAll) {
376 if (!events) {
377 return [];
378 }
379 return events.filter(function(e){
380 return showAll || e.message;
381 });
382 },
383
384 _isDead(bot){
385 if (bot && bot.is_dead) {
386 return "dead";
387 }
388 return "";
389 },
390
391 _luciLink: function(revision) {
392 if (!revision) {
393 return undefined;
394 }
395 return "https://github.com/luci/luci-py/commit/" + revision;
396
397 },
398
399 _numRows: function(arr) {
400 if (!arr || !arr.length) {
401 return 1;
402 }
403 return 1 + arr.length;
404 },
405
406 _prettyPrint: function(obj) {
407 obj = obj || {};
408 return JSON.stringify(obj, null, 2);
409 },
410
411 _quarantineMessage: function(bot) {
412 if (bot && bot.quarantined) {
413 var msg = bot.state.quarantined;
414 // Sometimes, the quarantined message is actually in "error". This
415 // happens when the bot code has thrown an exception.
416 if (msg === undefined || msg === "true" || msg === true) {
417 msg = this._attribute(bot, "error");
418 }
419 return msg || "True";
420 }
421 return "";
422 },
423
424 _shorten: function(str, length) {
425 if (!str || ! length) {
426 return "";
427 }
428 return str.substring(0, length);
429 },
430
431 _task: function(bot) {
432 return (bot && bot.task_id) || "idle";
433 },
434
435 _taskLink: function(task_id) {
436 // TODO(kjlubick): Migrate this to /newui/ when ready
437 if (task_id) {
438 return "/user/task/" + task_id;
439 }
440 return undefined;
441 },
442
443 _toggleState: function() {
444 this.set("_show_state", !this._show_state);
445 }
446
95 }); 447 });
96 })(); 448 })();
97 </script> 449 </script>
98 </dom-module> 450 </dom-module>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698