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

Side by Side Diff: appengine/swarming/elements/res/imp/taskpage/task-page.html

Issue 2337363004: Add task-page (Closed) Base URL: git@github.com:luci/luci-py@task-data
Patch Set: Alignment take 2 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 <task-page> 9 <task-page>
10 10
11 task-page shows the request, results, stats, and standard output of a task. 11 task-page shows the request, results, stats, and standard output of a task.
12 12
13 This is a top-level element. 13 This is a top-level element.
14 14
15 Properties: 15 Properties:
16 task_id: String, Used in testing to specify a task_id 16 task_id: String, Used in testing to specify a task_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-icon/iron-icon.html">
28 <link rel="import" href="/res/imp/bower_components/iron-icons/iron-icons.html">
29 <link rel="import" href="/res/imp/bower_components/paper-button/paper-button.htm l">
30 <link rel="import" href="/res/imp/bower_components/paper-dialog/paper-dialog.htm l">
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">
27 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> 33 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html">
28 34
29 <link rel="import" href="/res/imp/common/common-behavior.html"> 35 <link rel="import" href="/res/imp/common/common-behavior.html">
36 <link rel="import" href="/res/imp/common/single-page-style.html">
30 <link rel="import" href="/res/imp/common/swarming-app.html"> 37 <link rel="import" href="/res/imp/common/swarming-app.html">
38 <link rel="import" href="/res/imp/common/task-behavior.html">
31 <link rel="import" href="/res/imp/common/url-param.html"> 39 <link rel="import" href="/res/imp/common/url-param.html">
32 40
33 <link rel="import" href="task-page-data.html"> 41 <link rel="import" href="task-page-data.html">
34 42
35 <dom-module id="task-page"> 43 <dom-module id="task-page">
36 <template> 44 <template>
37 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style"> 45 <style include="iron-flex iron-flex-alignment swarming-app-style single-page -style task-style">
46 .milo {
47 width: calc(100% - 11px);
48 /** We don't control the milo site and it's on a different domain than
49 us, so there's no good way to avoid scrolling other than tell the iframe
50 it is really tall.*/
51 height: 2000px;
52 }
38 53
54 .left {
55 min-width: 550px;
56 }
57 .right {
58 min-width: 500px;
59 margin-top: 8px;
60 }
61
62 .expand {
63 min-width: 3em;
64 vertical-align: middle;
65 padding: .5em;
66 }
67
68 .code {
69 font-family: monospace;
70 }
71
72 .stdout {
73 white-space: pre-line;
74 padding: 2px;
75 }
76
77 .refresh_input {
78 padding: 0 5px;
79 }
80
81 .tabbed {
82 border: 3px solid #1F78B4;
83 margin-left: 5px;
84 min-height: 80vh;
85 }
39 </style> 86 </style>
40 87
41 <url-param name="id" 88 <url-param name="id"
42 value="{{task_id}}"> 89 value="{{task_id}}">
43 </url-param> 90 </url-param>
91 <url-param name="request_detail"
92 value="{{_request_detail}}">
93 </url-param>
94 <url-param name="show_raw"
95 value="{{_show_raw}}">
96 </url-param>
97 <url-param name="refresh"
98 value="{{_refresh}}"
99 default_value="10">
100 </url-param>
44 101
45 <swarming-app 102 <swarming-app
46 client_id="[[client_id]]" 103 client_id="[[client_id]]"
47 auth_headers="{{_auth_headers}}" 104 auth_headers="{{_auth_headers}}"
48 signed_in="{{_signed_in}}" 105 signed_in="{{_signed_in}}"
49 106
50 busy="[[_busy]]" 107 busy="[[_busy]]"
51 name="Swarming Task Page"> 108 name="Swarming Task Page">
52 109
53 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 110 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
54 111
55 <div hidden$="[[_not(_signed_in)]]"> 112 <div hidden$="[[_not(_signed_in)]]">
56 113
57 <task-page-data 114 <task-page-data
58 auth_headers="[[_auth_headers]]" 115 auth_headers="[[_auth_headers]]"
59 task_id="[[task_id]]" 116 task_id="[[task_id]]"
60 117
61 busy="{{_busy}}" 118 busy="{{_busy}}"
62 request="{{_request}}" 119 request="{{_request}}"
63 result="{{_result}}" 120 result="{{_result}}"
64 stdout="{{_stdout}}"> 121 stdout="{{_stdout}}">
65 </task-page-data> 122 </task-page-data>
66 123
67 <h1>Task Page Stub</h1> 124 <div class="horizontal layout wrap">
125 <div class="left flex">
126 <div class="horizontal layout">
127 <paper-input class="id_input" label="Task id" value="{{task_id}}"> </paper-input>
128 <button on-click="_refresh">
129 <iron-icon class="refresh" icon="icons:refresh"></iron-icon>
130 </button>
131 <button on-click="_retry"><span>Retry</span></button>
132 <button on-click="_cancel">Cancel</button>
133 </div>
134 <table>
135 <tr>
136 <td>Name</td>
137 <td>[[_request.name]]</td>
138 </tr>
139 <tr>
140 <td>State</td>
141 <td class$="[[_stateClass(_result)]]">[[_state(_result)]]</td>
142 </tr>
143 <tr>
144 <td>Created</td>
145 <td>[[_request.human_created_ts]]</td>
146 </tr>
147 <template is="dom-if" if="[[_wasPickedUp(_result)]]">
148 <tr>
149 <td>Started</td>
150 <td>[[_result.human_started_ts]]</td>
151 </tr>
152 </template>
153 <template is="dom-if" if="[[_wasNotPickedUp(_result)]]">
154 <tr>
155 <td>Expires</td>
156 <td>[[_expires(_request)]]</td>
157 </tr>
158 </template>
159 <template is="dom-if" if="[[_result.human_completed_ts]]">
160 <tr>
161 <td>Completed</td>
162 <td>[[_result.human_completed_ts]]</td>
163 </tr>
164 </template>
165 <template is="dom-if" if="[[_result.human_abandoned_ts]]">
166 <tr>
167 <td>Abandoned</td>
168 <td>[[_result.human_abandoned_ts]]</td>
169 </tr>
170 </template>
171 <tr>
172 <td>Last Updated</td>
173 <td>[[_result.human_modified_ts]]</td>
174 </tr>
175 <template is="dom-if" if="[[_result.deduped_from]]">
176 <tr>
177 <td><b>Deduped from</b></td>
178 <td>
179 <a href$="[[_taskLink(_result.deduped_from)]]">
180 [[_result.deduped_from]]
181 </a>
182 </td>
183 </tr>
184 </template>
185 <tr>
186 <td>Pending Time</td>
187 <td>[[_pending(_result)]]</td>
188 </tr>
189 <tr>
190 <td>Duration</td>
191 <td>[[_result.human_duration]]</td>
192 </tr>
193 <tr>
194 <td>Priority</td>
195 <td>[[_request.priority]]</td>
196 </tr>
197 <tr>
198 <td>User</td>
199 <td>[[_request.user]]</td>
200 </tr>
201 <tr>
202 <td>Authenticated</td>
203 <td>[[_request.authenticated]]</td>
204 </tr>
205 <template is="dom-if" if="[[_request.service_account]]">
206 <tr>
207 <td>Service Account</td>
208 <td>[[_request.service_account]]</td>
209 </tr>
210 </template>
211 <template is="dom-if" if="[[_request.properties.secret_bytes]]">
212 <tr>
213 <td>Secret Bytes</td>
214 <td>[[_request.properties.secret_bytes]]</td>
215 </tr>
216 </template>
217 <template is="dom-if" if="[[_request.parent_task_id]]">
218 <tr>
219 <td>Parent Task</td>
220 <td>
221 <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request .parent_task_id]]</a>
222 </td>
223 </tr>
224 </template>
225 <tr>
226 <td rowspan$="[[_rowspan(_request.properties.dimensions)]]">Requ ested Dimensions</td>
227 </tr>
228 <template is="dom-repeat" items="{{_request.properties.dimensions} }" as="dimension">
229 <tr>
230 <td><b>[[dimension.key]]:</b> [[dimension.value]]</td>
231 </tr>
232 </template>
233 <tr>
234 <td>Isolated Inputs</td>
235 <td>
236 <a href$="[[_isolateLink(_request.properties.inputs_ref)]]">
237 [[_request.properties.inputs_ref.isolated]]
238 </a>
239 </td>
240 </tr>
241 <template is="dom-if" if="[[_not(_request_detail)]]">
242 <tr>
243 <td>More Details</td>
244 <td>
245 <button on-click="_toggleDetails">
246 <iron-icon icon="icons:add-circle-outline"></iron-icon>
247 </button>
248 </td>
249 </tr>
250 </template>
251 <template is="dom-if" if="[[_request_detail]]">
252 <tr>
253 <td>Hide Details</td>
254 <td>
255 <button on-click="_toggleDetails">
256 <iron-icon icon="icons:remove-circle-outline"></iron-icon>
257 </button>
258 </td>
259 </tr>
260 </template>
261 <template is="dom-if" if="[[_request_detail]]">
262 <tr>
263 <td>Extra Args</td>
264 <td class="code">[[_extraArgs(_request)]]</td>
265 </tr>
266 <tr>
267 <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td>
268 </tr>
269 <template is="dom-repeat" items="{{_request.tags}}" as="tag">
270 <tr>
271 <td>[[tag]]</td>
272 </tr>
273 </template>
274
275 <tr>
276 <td>Execution timeout</td>
277 <td>[[_humanDuration(_request.properties.execution_timeout_sec s)]]</td>
278 </tr>
279 <tr>
280 <td>I/O timeout</td>
281 <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</t d>
282 </tr>
283 <tr>
284 <td>Grace period</td>
285 <td>[[_humanDuration(_request.properties.grace_period_secs)]]< /td>
286 </tr>
287
288 <tr>
289 <td>CIPD server</td>
290 <td>
291 <a href$="[[_request.properties.cipd_input.server]]">
292 [[_request.properties.cipd_input.server]]
293 </a>
294 </td>
295 </tr>
296 <tr>
297 <td>CIPD version</td>
298 <td>[[_request.properties.cipd_input.client_package.version]]< /td>
299 </tr>
300 <template is="dom-if" if="[[_wasPickedUp(_result)]]">
301 <tr>
302 <td>CIPD package name</td>
303 <td>[[_result.cipd_pins.client_package.package_name]]</td>
304 </tr>
305 </template>
306
307 <tr hidden$="[[_not(_request.properties.cipd_input)]]">
308 <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD package s</td>
309 </tr>
310 <template is="dom-repeat" items="[[_cipdPackages(_request,_resul t)]]" as="cipd">
311 <tr>
312 <td>[[cipd.path]]/</td>
313 </tr>
314 <tr>
315 <td><b>Requested:</b>[[cipd.requested]]</td>
316 </tr>
317 <tr hidden$="[[_wasNotPickedUp(_result)]]">
318 <td><b>Actual:</b>[[cipd.actual]]</td>
319 </tr>
320 </template>
321 </template>
322 </table>
323
324 <div class="title">Task Execution</div>
325 <template is="dom-if" if="[[_wasPickedUp(_result)]]">
326 <table>
327 <tr>
328 <td>Bot assigned to task</td>
329 <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]] </td>
330 </tr>
331 <tr>
332 <td rowspan$="[[_rowspan(_result.bot_dimensions)]]">Bot Dimens ions</td>
333 </tr>
334 <template is="dom-repeat" items="[[_result.bot_dimensions]]" as= "dimension">
335 <tr>
336 <td><b>[[dimension.key]]:</b> [[_join(dimension.value," | ") ]]</td>
337 </tr>
338 </template>
339
340 <tr>
341 <td>Exit code</td>
342 <td>[[_result.exit_code]]</td>
343 </tr>
344 <tr>
345 <td>Try number</td>
346 <td>[[_result.try_number]]</td>
347 </tr>
348 <tr>
349 <td>Failure</td>
350 <td class$="[[_failureClass(_result.failure)]]">[[_result.fail ure]]</td>
351 </tr>
352 <tr>
353 <td>Internal Failure</td>
354 <td class$="[[_internalClass(_result.internal_failure)]]">[[_r esult.internal_failure]]</td>
355 </tr>
356 <tr>
357 <td>Isolated Outputs</td>
358 <td>
359 <a href$="[[_isolateLink(_result.outputs_ref)]]">
360 [[_result.outputs_ref.isolated]]
361 </a>
362 </td>
363 </tr>
364 <tr>
365 <td>Bot version</td>
366 <td>[[_result.bot_version]]</td>
367 </tr>
368 <tr>
369 <td>Server version</td>
370 <td>[[_result.server_versions]]</td>
371 </tr>
372 </table>
373 </template>
374 <template is="dom-if" if="[[_wasNotPickedUp(_result)]]">
375 This space left blank until a bot is assigned to the task.
376 </template>
377
378 <template is="dom-if" if="[[_result.performance_stats]]">
379 <div class="title">Performance Stats</div>
380 <table>
381 <tr>
382 <td title="This includes time taken to download inputs, isolat e outputs, and setup CIPD">Total Overhead</td>
383 <td>[[_humanDuration(_result.performance_stats.bot_overhead)]] </td>
384 </tr>
385 <tr>
386 <td>Downloading Inputs From Isolate</td>
387 <td>[[_humanDuration(_result.performance_stats.isolated_downlo ad.duration)]]</td>
388 </tr>
389 <tr>
390 <td>Uploading Outputs To Isolate</td>
391 <td>[[_humanDuration(_result.performance_stats.isolated_upload .duration)]]</td>
392 </tr>
393 <tr>
394 <td>Initial bot cache</td>
395 <td>[[_result.performance_stats.isolated_download.initial_numb er_items]] items;
396 [[_bytes(_result.performance_stats.isolated_download.initial_s ize)]]</td>
397 </tr>
398 </table>
399 </template>
400 </div>
401
402 <div class="flex right">
403 <div class="horizontal layout">
404 <div class="tabs">
405 <paper-tabs selected="{{_show_raw}}" no-bar>
406 <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</pape r-tab>
407 <paper-tab>Raw Output</paper-tab>
408 </paper-tabs>
409 </div>
410
411 <paper-input
412 class="refresh_input"
413 label="Refresh Interval (seconds)"
414 value="{{_refresh}}"
415 auto-validate
416 min="1"
417 max="1000"
418 pattern="[0-9]+">
419 </paper-input>
420 </div>
421
422 <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]">
423 <iframe id="miloFrame" class="milo tabbed" src$="[[_getMiloLink(mi lo_prefix,task_id)]]"></iframe>
424 </template>
425 <template is="dom-if" if="[[_show_raw]]">
426 <div class="code stdout tabbed">[[_stdout]]</div>
427 </template>
428 </div>
429 </div>
68 </div> 430 </div>
69 431
70 </swarming-app> 432 </swarming-app>
71 433
72 </template> 434 </template>
73 <script> 435 <script>
74 (function(){ 436 (function(){
75 Polymer({ 437 Polymer({
76 is: 'task-page', 438 is: 'task-page',
77 439
78 behaviors: [ 440 behaviors: [
79 SwarmingBehaviors.CommonBehavior, 441 SwarmingBehaviors.CommonBehavior,
442 SwarmingBehaviors.TaskBehavior,
80 ], 443 ],
81 444
82 properties: { 445 properties: {
83 task_id: { 446 task_id: {
84 type: String, 447 type: String,
85 }, 448 },
86 client_id: { 449 client_id: {
87 type: String, 450 type: String,
88 }, 451 },
452 milo_prefix: {
453 type: String,
454 },
455
456 _request: {
457 type: Object,
458 observer: "_requestUpdated"
459 },
460 _request_detail: {
461 type: Boolean,
462 }
463 },
464
465 _bytes: function(sizeInBytes) {
466 return sk.human.bytes(sizeInBytes);
467 },
468
469 _cipdRowspan: function(request, result) {
470 if (!request || !request.properties || !request.properties.cipd_input) {
471 return 0;
472 }
473 // We always need to at least double the number of packages because we
474 // show the path and then the requested. If the actual package info
475 // is available, we triple the number of packages to account for that.
476 var rowSpan = (request.properties.cipd_input.packages || []).length;
477 if (result && result.cipd_pins && result.cipd_pins.packages) {
478 rowSpan *= 3;
479 } else {
480 rowSpan *= 2;
481 }
482 // Add one because rowSpan counts from 1.
483 return rowSpan + 1;
484 },
485
486 _cipdPackages: function(request, result) {
487 if (!request || !request.properties || !request.properties.cipd_input) {
488 return [];
489 }
490 var packages = request.properties.cipd_input.packages || [];
491 var actual = (result && result.cipd_pins && result.cipd_pins.packages) | | [];
492 packages.forEach(function(p) {
493 p.requested = p.package_name + ":" + p.version;
494 actual.forEach(function(c) {
495 if (c.path === p.path) {
496 p.actual = c.package_name + ":" + c.version;
497 }
498 });
499 });
500 return packages;
501 },
502
503 _expires: function(request) {
504 var delta = parseInt(request.expiration_secs);
505 if (delta) {
506 return sk.human.localeTime(new Date(request.created_ts.getTime() + del ta * 1000));
507 }
508 // Fall back to something
509 return request.expiration_secs + " seconds from created time";
510 },
511
512 _extraArgs: function(request) {
513 if (!request || !request.properties) {
514 return "";
515 }
516 var args = request.properties.extra_args || [];
517 return args.join(" ");
518 },
519
520 _failureClass: function(failure) {
521 if (failure) {
522 return "failed_task";
523 }
524 return "";
525 },
526
527 _getMiloLink: function(prefix,id) {
528 if (!prefix) {
529 return undefined;
530 }
531 return prefix + id;
532 },
533
534 _internalClass: function(failure) {
535 if (failure) {
536 return "exception";
537 }
538 return "";
539 },
540
541 _isolateLink: function(ref) {
542 if (!ref || !ref.isolatedserver) {
543 return undefined;
544 }
545 return ref.isolatedserver + "/browse?namespace="+ref.namespace +
546 "&hash=" + ref.isolated;
547 },
548
549 _join: function(arr, s) {
550 arr = arr || [];
551 return arr.join(s);
552 },
553
554 _noMilo: function(result) {
555 return !this._tag(result, "allow_milo");
556 },
557
558 _pending: function(result) {
559 if (!result.created_ts) {
560 return "";
561 }
562 var end = result.started_ts || result.abandoned_ts || new Date();
563 // In the case of deduplicated tasks, started_ts comes before the task.
564 if (end <= result.created_ts) {
565 return "0s";
566 }
567 return this._timeDiffExact(result.created_ts, end);
568 },
569
570 _requestUpdated: function(request) {
571 if (this._noMilo(request)) {
572 this.set("_show_raw", 1);
573 }
574 },
575
576 _rowspan: function(dims) {
577 dims = dims || [];
578 return dims.length + 1;
579 },
580
581 _supportsMilo: function(request, showRaw) {
582 return !showRaw && request && this._tag(request, "allow_milo");
583 },
584
585 _state: function(result) {
586 if (!result) {
587 return "";
588 }
589 if (result.state === this.COMPLETED) {
590 if (result.failure) {
591 return this.COMPLETED_FAILURE;
592 }
593 if (result.try_number === "0") {
594 return this.COMPLETED_DEDUPED;
595 }
596 return this.COMPLETED_SUCCESS;
597 }
598 return result.state;
599 },
600
601 _stateClass: function(result) {
602 return this.stateClass(this._state(result));
603 },
604
605 _toggleDetails: function() {
606 this.set("_request_detail", !this._request_detail);
607 },
608
609 _tag: function(result, col) {
610 if (!result || !result.tagMap) {
611 return undefined;
612 }
613 return result.tagMap[col];
614 },
615
616 _wasPickedUp: function(result) {
617 return result && result.state !== this.PENDING && result.state !== this. CANCELED && result.state != this.EXPIRED;
618 },
619
620 _wasNotPickedUp: function(result) {
621 return result && !this._wasPickedUp(result);
89 }, 622 },
90 }); 623 });
91 })(); 624 })();
92 </script> 625 </script>
93 </dom-module> 626 </dom-module>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698