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

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: wrong branch 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
« no previous file with comments | « appengine/swarming/elements/res/imp/common/single-page-style.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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-checkbox/paper-checkbox .html">
31 <link rel="import" href="/res/imp/bower_components/paper-dialog/paper-dialog.htm l">
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">
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"> 36 <link rel="import" href="/res/imp/common/common-behavior.html">
37 <link rel="import" href="/res/imp/common/single-page-style.html">
30 <link rel="import" href="/res/imp/common/swarming-app.html"> 38 <link rel="import" href="/res/imp/common/swarming-app.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 43
36 <dom-module id="task-page"> 44 <dom-module id="task-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 swarming-app-style single-page -style">
47 .milo {
48 width: calc(100% - 11px);
49 /** We don't control the milo site and it's on a different domain than
50 us, so there's no good way to avoid scrolling other than tell the iframe
51 it is really tall.*/
52 height: 2000px;
53 }
39 54
55 .left {
56 min-width: 550px;
57 }
58 .right {
59 min-width: 500px;
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 }
40 </style> 86 </style>
41 87
42 <url-param name="id" 88 <url-param name="id"
43 value="{{task_id}}"> 89 value="{{task_id}}">
44 </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>
45 101
46 <swarming-app 102 <swarming-app
47 client_id="[[client_id]]" 103 client_id="[[client_id]]"
48 auth_headers="{{_auth_headers}}" 104 auth_headers="{{_auth_headers}}"
49 signed_in="{{_signed_in}}" 105 signed_in="{{_signed_in}}"
50 106
51 busy="[[_busy]]" 107 busy="[[_busy]]"
52 name="Swarming Task Page"> 108 name="Swarming Task Page">
53 109
54 <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>
55 111
56 <div hidden$="[[_not(_signed_in)]]"> 112 <div hidden$="[[_not(_signed_in)]]">
57 113
58 <task-page-data 114 <task-page-data
59 auth_headers="[[_auth_headers]]" 115 auth_headers="[[_auth_headers]]"
60 task_id="[[task_id]]" 116 task_id="[[task_id]]"
61 117
62 busy="{{_busy}}" 118 busy="{{_busy}}"
63 request="{{_request}}" 119 request="{{_request}}"
64 result="{{_result}}" 120 result="{{_result}}"
65 stdout="{{_stdout}}"> 121 stdout="{{_stdout}}">
66 </task-page-data> 122 </task-page-data>
67 123
68 <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)]]">
stephana 2016/09/20 13:16:35 Could these dom-if's be replaced with hidden ?
kjlubick 2016/09/20 19:44:25 When I use the hidden approach, they are visible b
stephana 2016/09/20 20:07:17 Acknowledged.
148 <tr>
149 <td>Started</td>
150 <td>[[_result.human_started_ts]]</td>
151 </tr>
152 </template>
153 <template is="dom-if" if="[[_hasntFinished(_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="[[_request_detail]]">
242 <tr>
243 <td>Extra Args</td>
244 <td class="code">[[_extraArgs(_request)]]</td>
245 </tr>
246 <tr>
247 <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td>
248 </tr>
249 <template is="dom-repeat" items="{{_request.tags}}" as="tag">
250 <tr>
251 <td>[[tag]]</td>
252 </tr>
253 </template>
254
255 <tr>
256 <td>Execution timeout</td>
257 <td>[[_humanDuration(_request.properties.execution_timeout_sec s)]]</td>
258 </tr>
259 <tr>
260 <td>I/O timeout</td>
261 <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</t d>
262 </tr>
263 <tr>
264 <td>Grace period</td>
265 <td>[[_humanDuration(_request.properties.grace_period_secs)]]< /td>
266 </tr>
267
268 <tr>
269 <td>CIPD server</td>
270 <td>
271 <a href$="[[_request.properties.cipd_input.server]]">
272 [[_request.properties.cipd_input.server]]
273 </a>
274 </td>
275 </tr>
276 <tr>
277 <td>CIPD version</td>
278 <td>[[_request.properties.cipd_input.client_package.version]]< /td>
279 </tr>
280 <template is="dom-if" if="[[_wasPickedUp(_result)]]">
281 <tr>
282 <td>CIPD package name</td>
283 <td>[[_result.cipd_pins.client_package.package_name]]</td>
284 </tr>
285 </template>
286
287 <tr hidden$="[[_not(_request.properties.cipd_input)]]">
288 <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD package s</td>
289 </tr>
290 <template is="dom-repeat" items="[[_cipdPackages(_request,_resul t)]]" as="cipd">
291 <tr>
292 <td>[[cipd.path]]/</td>
293 </tr>
294 <tr>
295 <td><b>Requested:</b>[[cipd.requested]]</td>
296 </tr>
297 <tr hidden$="[[_wasNotPickedUp(_result)]]">
298 <td><b>Actual:</b>[[cipd.actual]]</td>
299 </tr>
300 </template>
301 </template>
302 <template is="dom-if" if="[[_not(_request_detail)]]">
303 <tr>
304 <td>More Details</td>
305 <td>
306 <button on-click="_toggleDetails">
307 <iron-icon icon="icons:add-circle-outline"></iron-icon>
308 </button>
309 </td>
310 </tr>
311 </template>
312 <template is="dom-if" if="[[_request_detail]]">
313 <tr>
314 <td>Hide Details</td>
315 <td>
316 <button on-click="_toggleDetails">
317 <iron-icon icon="icons:remove-circle-outline"></iron-icon>
318 </button>
319 </td>
320 </tr>
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>
69 </div> 430 </div>
70 431
71 </swarming-app> 432 </swarming-app>
72 433
73 </template> 434 </template>
74 <script> 435 <script>
75 (function(){ 436 (function(){
76 437
77
78 Polymer({ 438 Polymer({
79 is: 'task-page', 439 is: 'task-page',
80 440
81 behaviors: [ 441 behaviors: [
82 SwarmingBehaviors.CommonBehavior, 442 SwarmingBehaviors.CommonBehavior,
83 ], 443 ],
84 444
85 properties: { 445 properties: {
86 task_id: { 446 task_id: {
87 type: String, 447 type: String,
88 }, 448 },
89 client_id: { 449 client_id: {
90 type: String, 450 type: String,
91 }, 451 },
452 milo_prefix: {
453 type: String,
454 },
92 455
456 _request: {
457 type: Object,
458 observer: "_requestUpdated"
459 },
460 _request_detail: {
461 type: Boolean,
462 }
93 }, 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 _hasntFinished: function(result) {
535 return result && (result.state === "RUNNING" || result.state === "PENDIN G");
536 },
537
538 _internalClass: function(failure) {
539 if (failure) {
540 return "exception";
541 }
542 return "";
543 },
544
545 _isolateLink: function(ref) {
546 if (!ref || !ref.isolatedserver) {
547 return undefined;
548 }
549 return ref.isolatedserver + "/browse?namespace="+ref.namespace +
550 "&hash=" + ref.isolated;
551 },
552
553 _join: function(arr, s) {
554 arr = arr || [];
555 return arr.join(s);
556 },
557
558 _noMilo: function(result) {
559 return !this._tag(result, "allow_milo");
560 },
561
562 _pending: function(result) {
563 if (!result.created_ts) {
564 return "";
565 }
566 var end = result.started_ts || result.abandoned_ts || new Date();
567 // In the case of deduplicated tasks, started_ts comes before the task.
568 if (end <= result.created_ts) {
569 return "0s";
570 }
571 return this._timeDiffExact(result.created_ts, end);
572 },
573
574 _requestUpdated: function(request) {
575 if (this._noMilo(request)) {
576 this.set("_show_raw", 1);
577 }
578 },
579
580 _rowspan: function(dims) {
581 dims = dims || [];
582 return dims.length + 1;
583 },
584
585 _supportsMilo: function(request, showRaw) {
586 return !showRaw && request && this._tag(request, "allow_milo");
587 },
588
589 _state: function(result) {
590 if (!result) {
591 return "";
592 }
593 if (result.state === "COMPLETED") {
stephana 2016/09/20 13:16:35 IMO it's preferable to use use constants instead o
kjlubick 2016/09/20 19:44:25 Done. See task-behavior
594 if (result.failure) {
595 return "COMPLETED (FAILURE)";
596 }
597 if (result.try_number === "0") {
598 return "COMPLETED (DEDUPED)";
599 }
600 return "COMPLETED (SUCCESS)";
601 }
602 return result.state;
603 },
604
605 _stateClass: function(result) {
606 var state = this._state(result);
607 if (state === "CANCELED" ||state === "TIMED_OUT" || state === "EXPIRED") {
stephana 2016/09/20 13:16:35 Instead of many if-statements you could have a loo
kjlubick 2016/09/20 19:44:25 Moved to task-behavior. I don't think the object
608 return "exception";
609 }
610 if (state === "BOT_DIED") {
611 return "bot_died";
612 }
613 if (state === "COMPLETED (FAILURE)") {
614 return "failed_task";
615 }
616 if (state === "RUNNING" || state === "PENDING") {
617 return "pending_task";
618 }
619 return "";
620 },
621
622 _toggleDetails: function() {
623 this.set("_request_detail", !this._request_detail);
624 },
625
626 _tag: function(result, col) {
627 if (!result || !result.tagMap) {
628 return undefined;
629 }
630 return result.tagMap[col];
631 },
632
633 _wasPickedUp: function(result) {
634 return result && result.state !== "PENDING" && result.state !== "CANCELE D" && result.state != "EXPIRED";
635 },
636
637 _wasNotPickedUp: function(result) {
638 return result && !this._wasPickedUp(result);
639 }
640
94 }); 641 });
95 })(); 642 })();
96 </script> 643 </script>
97 </dom-module> 644 </dom-module>
OLDNEW
« no previous file with comments | « appengine/swarming/elements/res/imp/common/single-page-style.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698