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

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

Powered by Google App Engine
This is Rietveld 408576698