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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: appengine/swarming/elements/res/imp/taskpage/task-page.html
diff --git a/appengine/swarming/elements/res/imp/taskpage/task-page.html b/appengine/swarming/elements/res/imp/taskpage/task-page.html
index bee2aa92c6088bef0aef8f0324822554e9f7eeb7..d5cee63f12742ff6a2f36f64712003cd86dc91be 100644
--- a/appengine/swarming/elements/res/imp/taskpage/task-page.html
+++ b/appengine/swarming/elements/res/imp/taskpage/task-page.html
@@ -24,23 +24,80 @@
None.
-->
+<link rel="import" href="/res/imp/bower_components/iron-icon/iron-icon.html">
+<link rel="import" href="/res/imp/bower_components/iron-icons/iron-icons.html">
+<link rel="import" href="/res/imp/bower_components/paper-button/paper-button.html">
+<link rel="import" href="/res/imp/bower_components/paper-dialog/paper-dialog.html">
+<link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html">
+<link rel="import" href="/res/imp/bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="/res/imp/bower_components/polymer/polymer.html">
<link rel="import" href="/res/imp/common/common-behavior.html">
+<link rel="import" href="/res/imp/common/single-page-style.html">
<link rel="import" href="/res/imp/common/swarming-app.html">
+<link rel="import" href="/res/imp/common/task-behavior.html">
<link rel="import" href="/res/imp/common/url-param.html">
<link rel="import" href="task-page-data.html">
<dom-module id="task-page">
<template>
- <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style">
+ <style include="iron-flex iron-flex-alignment swarming-app-style single-page-style task-style">
+ .milo {
+ width: calc(100% - 11px);
+ /** We don't control the milo site and it's on a different domain than
+ us, so there's no good way to avoid scrolling other than tell the iframe
+ it is really tall.*/
+ height: 2000px;
+ }
+ .left {
+ min-width: 550px;
+ }
+ .right {
+ min-width: 500px;
+ margin-top: 8px;
+ }
+
+ .expand {
+ min-width: 3em;
+ vertical-align: middle;
+ padding: .5em;
+ }
+
+ .code {
+ font-family: monospace;
+ }
+
+ .stdout {
+ white-space: pre-line;
+ padding: 2px;
+ }
+
+ .refresh_input {
+ padding: 0 5px;
+ }
+
+ .tabbed {
+ border: 3px solid #1F78B4;
+ margin-left: 5px;
+ min-height: 80vh;
+ }
</style>
<url-param name="id"
value="{{task_id}}">
</url-param>
+ <url-param name="request_detail"
+ value="{{_request_detail}}">
+ </url-param>
+ <url-param name="show_raw"
+ value="{{_show_raw}}">
+ </url-param>
+ <url-param name="refresh"
+ value="{{_refresh}}"
+ default_value="10">
+ </url-param>
<swarming-app
client_id="[[client_id]]"
@@ -64,7 +121,312 @@
stdout="{{_stdout}}">
</task-page-data>
- <h1>Task Page Stub</h1>
+ <div class="horizontal layout wrap">
+ <div class="left flex">
+ <div class="horizontal layout">
+ <paper-input class="id_input" label="Task id" value="{{task_id}}"></paper-input>
+ <button on-click="_refresh">
+ <iron-icon class="refresh" icon="icons:refresh"></iron-icon>
+ </button>
+ <button on-click="_retry"><span>Retry</span></button>
+ <button on-click="_cancel">Cancel</button>
+ </div>
+ <table>
+ <tr>
+ <td>Name</td>
+ <td>[[_request.name]]</td>
+ </tr>
+ <tr>
+ <td>State</td>
+ <td class$="[[_stateClass(_result)]]">[[_state(_result)]]</td>
+ </tr>
+ <tr>
+ <td>Created</td>
+ <td>[[_request.human_created_ts]]</td>
+ </tr>
+ <template is="dom-if" if="[[_wasPickedUp(_result)]]">
+ <tr>
+ <td>Started</td>
+ <td>[[_result.human_started_ts]]</td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_wasNotPickedUp(_result)]]">
+ <tr>
+ <td>Expires</td>
+ <td>[[_expires(_request)]]</td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_result.human_completed_ts]]">
+ <tr>
+ <td>Completed</td>
+ <td>[[_result.human_completed_ts]]</td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_result.human_abandoned_ts]]">
+ <tr>
+ <td>Abandoned</td>
+ <td>[[_result.human_abandoned_ts]]</td>
+ </tr>
+ </template>
+ <tr>
+ <td>Last Updated</td>
+ <td>[[_result.human_modified_ts]]</td>
+ </tr>
+ <template is="dom-if" if="[[_result.deduped_from]]">
+ <tr>
+ <td><b>Deduped from</b></td>
+ <td>
+ <a href$="[[_taskLink(_result.deduped_from)]]">
+ [[_result.deduped_from]]
+ </a>
+ </td>
+ </tr>
+ </template>
+ <tr>
+ <td>Pending Time</td>
+ <td>[[_pending(_result)]]</td>
+ </tr>
+ <tr>
+ <td>Duration</td>
+ <td>[[_result.human_duration]]</td>
+ </tr>
+ <tr>
+ <td>Priority</td>
+ <td>[[_request.priority]]</td>
+ </tr>
+ <tr>
+ <td>User</td>
+ <td>[[_request.user]]</td>
+ </tr>
+ <tr>
+ <td>Authenticated</td>
+ <td>[[_request.authenticated]]</td>
+ </tr>
+ <template is="dom-if" if="[[_request.service_account]]">
+ <tr>
+ <td>Service Account</td>
+ <td>[[_request.service_account]]</td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_request.properties.secret_bytes]]">
+ <tr>
+ <td>Secret Bytes</td>
+ <td>[[_request.properties.secret_bytes]]</td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_request.parent_task_id]]">
+ <tr>
+ <td>Parent Task</td>
+ <td>
+ <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request.parent_task_id]]</a>
+ </td>
+ </tr>
+ </template>
+ <tr>
+ <td rowspan$="[[_rowspan(_request.properties.dimensions)]]">Requested Dimensions</td>
+ </tr>
+ <template is="dom-repeat" items="{{_request.properties.dimensions}}" as="dimension">
+ <tr>
+ <td><b>[[dimension.key]]:</b> [[dimension.value]]</td>
+ </tr>
+ </template>
+ <tr>
+ <td>Isolated Inputs</td>
+ <td>
+ <a href$="[[_isolateLink(_request.properties.inputs_ref)]]">
+ [[_request.properties.inputs_ref.isolated]]
+ </a>
+ </td>
+ </tr>
+ <template is="dom-if" if="[[_not(_request_detail)]]">
+ <tr>
+ <td>More Details</td>
+ <td>
+ <button on-click="_toggleDetails">
+ <iron-icon icon="icons:add-circle-outline"></iron-icon>
+ </button>
+ </td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_request_detail]]">
+ <tr>
+ <td>Hide Details</td>
+ <td>
+ <button on-click="_toggleDetails">
+ <iron-icon icon="icons:remove-circle-outline"></iron-icon>
+ </button>
+ </td>
+ </tr>
+ </template>
+ <template is="dom-if" if="[[_request_detail]]">
+ <tr>
+ <td>Extra Args</td>
+ <td class="code">[[_extraArgs(_request)]]</td>
+ </tr>
+ <tr>
+ <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td>
+ </tr>
+ <template is="dom-repeat" items="{{_request.tags}}" as="tag">
+ <tr>
+ <td>[[tag]]</td>
+ </tr>
+ </template>
+
+ <tr>
+ <td>Execution timeout</td>
+ <td>[[_humanDuration(_request.properties.execution_timeout_secs)]]</td>
+ </tr>
+ <tr>
+ <td>I/O timeout</td>
+ <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</td>
+ </tr>
+ <tr>
+ <td>Grace period</td>
+ <td>[[_humanDuration(_request.properties.grace_period_secs)]]</td>
+ </tr>
+
+ <tr>
+ <td>CIPD server</td>
+ <td>
+ <a href$="[[_request.properties.cipd_input.server]]">
+ [[_request.properties.cipd_input.server]]
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td>CIPD version</td>
+ <td>[[_request.properties.cipd_input.client_package.version]]</td>
+ </tr>
+ <template is="dom-if" if="[[_wasPickedUp(_result)]]">
+ <tr>
+ <td>CIPD package name</td>
+ <td>[[_result.cipd_pins.client_package.package_name]]</td>
+ </tr>
+ </template>
+
+ <tr hidden$="[[_not(_request.properties.cipd_input)]]">
+ <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD packages</td>
+ </tr>
+ <template is="dom-repeat" items="[[_cipdPackages(_request,_result)]]" as="cipd">
+ <tr>
+ <td>[[cipd.path]]/</td>
+ </tr>
+ <tr>
+ <td><b>Requested:</b>[[cipd.requested]]</td>
+ </tr>
+ <tr hidden$="[[_wasNotPickedUp(_result)]]">
+ <td><b>Actual:</b>[[cipd.actual]]</td>
+ </tr>
+ </template>
+ </template>
+ </table>
+
+ <div class="title">Task Execution</div>
+ <template is="dom-if" if="[[_wasPickedUp(_result)]]">
+ <table>
+ <tr>
+ <td>Bot assigned to task</td>
+ <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]]</td>
+ </tr>
+ <tr>
+ <td rowspan$="[[_rowspan(_result.bot_dimensions)]]">Bot Dimensions</td>
+ </tr>
+ <template is="dom-repeat" items="[[_result.bot_dimensions]]" as="dimension">
+ <tr>
+ <td><b>[[dimension.key]]:</b> [[_join(dimension.value," | ")]]</td>
+ </tr>
+ </template>
+
+ <tr>
+ <td>Exit code</td>
+ <td>[[_result.exit_code]]</td>
+ </tr>
+ <tr>
+ <td>Try number</td>
+ <td>[[_result.try_number]]</td>
+ </tr>
+ <tr>
+ <td>Failure</td>
+ <td class$="[[_failureClass(_result.failure)]]">[[_result.failure]]</td>
+ </tr>
+ <tr>
+ <td>Internal Failure</td>
+ <td class$="[[_internalClass(_result.internal_failure)]]">[[_result.internal_failure]]</td>
+ </tr>
+ <tr>
+ <td>Isolated Outputs</td>
+ <td>
+ <a href$="[[_isolateLink(_result.outputs_ref)]]">
+ [[_result.outputs_ref.isolated]]
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td>Bot version</td>
+ <td>[[_result.bot_version]]</td>
+ </tr>
+ <tr>
+ <td>Server version</td>
+ <td>[[_result.server_versions]]</td>
+ </tr>
+ </table>
+ </template>
+ <template is="dom-if" if="[[_wasNotPickedUp(_result)]]">
+ This space left blank until a bot is assigned to the task.
+ </template>
+
+ <template is="dom-if" if="[[_result.performance_stats]]">
+ <div class="title">Performance Stats</div>
+ <table>
+ <tr>
+ <td title="This includes time taken to download inputs, isolate outputs, and setup CIPD">Total Overhead</td>
+ <td>[[_humanDuration(_result.performance_stats.bot_overhead)]]</td>
+ </tr>
+ <tr>
+ <td>Downloading Inputs From Isolate</td>
+ <td>[[_humanDuration(_result.performance_stats.isolated_download.duration)]]</td>
+ </tr>
+ <tr>
+ <td>Uploading Outputs To Isolate</td>
+ <td>[[_humanDuration(_result.performance_stats.isolated_upload.duration)]]</td>
+ </tr>
+ <tr>
+ <td>Initial bot cache</td>
+ <td>[[_result.performance_stats.isolated_download.initial_number_items]] items;
+ [[_bytes(_result.performance_stats.isolated_download.initial_size)]]</td>
+ </tr>
+ </table>
+ </template>
+ </div>
+
+ <div class="flex right">
+ <div class="horizontal layout">
+ <div class="tabs">
+ <paper-tabs selected="{{_show_raw}}" no-bar>
+ <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</paper-tab>
+ <paper-tab>Raw Output</paper-tab>
+ </paper-tabs>
+ </div>
+
+ <paper-input
+ class="refresh_input"
+ label="Refresh Interval (seconds)"
+ value="{{_refresh}}"
+ auto-validate
+ min="1"
+ max="1000"
+ pattern="[0-9]+">
+ </paper-input>
+ </div>
+
+ <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]">
+ <iframe id="miloFrame" class="milo tabbed" src$="[[_getMiloLink(milo_prefix,task_id)]]"></iframe>
+ </template>
+ <template is="dom-if" if="[[_show_raw]]">
+ <div class="code stdout tabbed">[[_stdout]]</div>
+ </template>
+ </div>
+ </div>
</div>
</swarming-app>
@@ -77,6 +439,7 @@
behaviors: [
SwarmingBehaviors.CommonBehavior,
+ SwarmingBehaviors.TaskBehavior,
],
properties: {
@@ -86,6 +449,176 @@
client_id: {
type: String,
},
+ milo_prefix: {
+ type: String,
+ },
+
+ _request: {
+ type: Object,
+ observer: "_requestUpdated"
+ },
+ _request_detail: {
+ type: Boolean,
+ }
+ },
+
+ _bytes: function(sizeInBytes) {
+ return sk.human.bytes(sizeInBytes);
+ },
+
+ _cipdRowspan: function(request, result) {
+ if (!request || !request.properties || !request.properties.cipd_input) {
+ return 0;
+ }
+ // We always need to at least double the number of packages because we
+ // show the path and then the requested. If the actual package info
+ // is available, we triple the number of packages to account for that.
+ var rowSpan = (request.properties.cipd_input.packages || []).length;
+ if (result && result.cipd_pins && result.cipd_pins.packages) {
+ rowSpan *= 3;
+ } else {
+ rowSpan *= 2;
+ }
+ // Add one because rowSpan counts from 1.
+ return rowSpan + 1;
+ },
+
+ _cipdPackages: function(request, result) {
+ if (!request || !request.properties || !request.properties.cipd_input) {
+ return [];
+ }
+ var packages = request.properties.cipd_input.packages || [];
+ var actual = (result && result.cipd_pins && result.cipd_pins.packages) || [];
+ packages.forEach(function(p) {
+ p.requested = p.package_name + ":" + p.version;
+ actual.forEach(function(c) {
+ if (c.path === p.path) {
+ p.actual = c.package_name + ":" + c.version;
+ }
+ });
+ });
+ return packages;
+ },
+
+ _expires: function(request) {
+ var delta = parseInt(request.expiration_secs);
+ if (delta) {
+ return sk.human.localeTime(new Date(request.created_ts.getTime() + delta * 1000));
+ }
+ // Fall back to something
+ return request.expiration_secs + " seconds from created time";
+ },
+
+ _extraArgs: function(request) {
+ if (!request || !request.properties) {
+ return "";
+ }
+ var args = request.properties.extra_args || [];
+ return args.join(" ");
+ },
+
+ _failureClass: function(failure) {
+ if (failure) {
+ return "failed_task";
+ }
+ return "";
+ },
+
+ _getMiloLink: function(prefix,id) {
+ if (!prefix) {
+ return undefined;
+ }
+ return prefix + id;
+ },
+
+ _internalClass: function(failure) {
+ if (failure) {
+ return "exception";
+ }
+ return "";
+ },
+
+ _isolateLink: function(ref) {
+ if (!ref || !ref.isolatedserver) {
+ return undefined;
+ }
+ return ref.isolatedserver + "/browse?namespace="+ref.namespace +
+ "&hash=" + ref.isolated;
+ },
+
+ _join: function(arr, s) {
+ arr = arr || [];
+ return arr.join(s);
+ },
+
+ _noMilo: function(result) {
+ return !this._tag(result, "allow_milo");
+ },
+
+ _pending: function(result) {
+ if (!result.created_ts) {
+ return "";
+ }
+ var end = result.started_ts || result.abandoned_ts || new Date();
+ // In the case of deduplicated tasks, started_ts comes before the task.
+ if (end <= result.created_ts) {
+ return "0s";
+ }
+ return this._timeDiffExact(result.created_ts, end);
+ },
+
+ _requestUpdated: function(request) {
+ if (this._noMilo(request)) {
+ this.set("_show_raw", 1);
+ }
+ },
+
+ _rowspan: function(dims) {
+ dims = dims || [];
+ return dims.length + 1;
+ },
+
+ _supportsMilo: function(request, showRaw) {
+ return !showRaw && request && this._tag(request, "allow_milo");
+ },
+
+ _state: function(result) {
+ if (!result) {
+ return "";
+ }
+ if (result.state === this.COMPLETED) {
+ if (result.failure) {
+ return this.COMPLETED_FAILURE;
+ }
+ if (result.try_number === "0") {
+ return this.COMPLETED_DEDUPED;
+ }
+ return this.COMPLETED_SUCCESS;
+ }
+ return result.state;
+ },
+
+ _stateClass: function(result) {
+ return this.stateClass(this._state(result));
+ },
+
+ _toggleDetails: function() {
+ this.set("_request_detail", !this._request_detail);
+ },
+
+ _tag: function(result, col) {
+ if (!result || !result.tagMap) {
+ return undefined;
+ }
+ return result.tagMap[col];
+ },
+
+ _wasPickedUp: function(result) {
+ return result && result.state !== this.PENDING && result.state !== this.CANCELED && result.state != this.EXPIRED;
+ },
+
+ _wasNotPickedUp: function(result) {
+ return result && !this._wasPickedUp(result);
},
});
})();

Powered by Google App Engine
This is Rietveld 408576698