| Index: appengine/swarming/ui/res/imp/tasklist/task-list-summary.html
|
| diff --git a/appengine/swarming/ui/res/imp/tasklist/task-list-summary.html b/appengine/swarming/ui/res/imp/tasklist/task-list-summary.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..765ff0f4407f194897f85bee93f6164521c4063b
|
| --- /dev/null
|
| +++ b/appengine/swarming/ui/res/imp/tasklist/task-list-summary.html
|
| @@ -0,0 +1,312 @@
|
| +<!--
|
| + This in an HTML Import-able file that contains the definition
|
| + of the following elements:
|
| +
|
| + <task-list-summary>
|
| +
|
| + Usage:
|
| +
|
| + <task-list-summary></task-list-summary>
|
| +
|
| + This element summarizes and displays the results of the current query.
|
| + It links to some global queries (e.g. all running tasks) and some
|
| + sub queries (e.g. all pending tasks that match the rest of the
|
| + specified tags.)
|
| +
|
| + Properties:
|
| + // inputs
|
| + auth_headers: Object, the OAuth2 header to include in the request. This
|
| + should come from swarming-app.
|
| + columns: Array<String>, the columns the user has selected. Used to create
|
| + the links.
|
| + count_params: Object, representing the query params sent to the server based
|
| + on all the filterable items (e.g. tags). See task-filters for the
|
| + schema.
|
| + num_tasks: Number, The number of tasks shown (after filtering).
|
| + sort: String, the user's current sort string. Used to create the links.
|
| +
|
| + // outputs
|
| + busy: Boolean, if there are any network requests pending.
|
| +
|
| + Methods:
|
| + None.
|
| +
|
| + Events:
|
| + None.
|
| +-->
|
| +
|
| +<link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html">
|
| +
|
| +<link rel="import" href="/res/imp/common/swarming-app.html">
|
| +<link rel="import" href="/res/imp/common/common-behavior.html">
|
| +
|
| +<dom-module id="task-list-summary">
|
| + <template>
|
| + <style include="swarming-app-style iron-flex">
|
| + :host {
|
| + display: block;
|
| + border-left: 1px solid black;
|
| + padding: 5px 5px;
|
| + font-family: sans-serif;
|
| + }
|
| + .header {
|
| + font-size: 1.2em;
|
| + font-weight: bold;
|
| + }
|
| + .column.left {
|
| + margin-left: 10px;
|
| + }
|
| + .right {
|
| + text-align: right;
|
| + }
|
| + .left {
|
| + text-align: left;
|
| + }
|
| + </style>
|
| +
|
| + <div class="horizontal layout">
|
| +
|
| + <div class="column">
|
| + <table>
|
| + <thead>
|
| + <th class="header right" colspan=2>Selected</th>
|
| + </thead>
|
| + <tr>
|
| + <td class="right">
|
| + Displayed:
|
| + </td>
|
| + <td class="left">[[num_tasks]]</td>
|
| + </tr>
|
| + <tr title="By default, these counts are from the last 24 hours">
|
| + <td class="right" >
|
| + Total:
|
| + </td>
|
| + <td class="left">[[_selected_exact.count]]</td>
|
| + </tr>
|
| + <template is="dom-repeat" items="[[_selected_summary]]" as="item" index-as="idx">
|
| + <tr title="By default, these counts are from the last 24 hours">
|
| + <td class="right">
|
| + <a href$="[[_makeURL(item.name,'true',columns.*,sort)]]">[[item.human]]</a>:
|
| + </td>
|
| + <td class="left">[[_idx(_selected_counts, idx, _selected_counts.*)]]</td>
|
| + </tr>
|
| + </template>
|
| + </table>
|
| + </div>
|
| +
|
| + <div class="left column">
|
| + <table>
|
| + <thead>
|
| + <!-- TODO(kjlubick) when user can update time, use the human readable value instead of 12h-->
|
| + <th class="header right" colspan=2>All Tasks in last 24h</th>
|
| + </thead>
|
| + <template is="dom-repeat" items="[[_all_summary]]" as="item" index-as="idx">
|
| + <tr title="By default, this is the last 24 hours">
|
| + <td class="right">
|
| + <a href$="[[_makeURL(item.name,'',columns.*,sort)]]">[[item.human]]</a>:
|
| + </td>
|
| + <td class="left">[[_idx(_all_counts, idx, _all_counts.*)]]</td>
|
| + </tr>
|
| + </template>
|
| + </table>
|
| + </div>
|
| +
|
| + </div>
|
| +
|
| + </template>
|
| + <script>
|
| + (function(){
|
| + var ALL_TASKS_SUMMARY = [
|
| + {name:"ALL", human:"All"},
|
| + {name:"BOT_DIED", human:"Bot Died"},
|
| + {name:"CANCELED", human:"Canceled"},
|
| + {name:"COMPLETED_SUCCESS", human:"Completed (Success)"},
|
| + {name:"COMPLETED_FAILURE", human:"Completed (Failure)"},
|
| + {name:"DEDUPED", human:"Deduplicated"},
|
| + {name:"EXPIRED", human:"Expired"},
|
| + {name:"PENDING", human:"Pending"},
|
| + {name:"RUNNING", human:"Running"},
|
| + {name:"TIMED_OUT", human:"Timed Out"},
|
| + ];
|
| + var SELECTED_TASKS_SUMMARY = [
|
| + {name:"BOT_DIED", human:"Bot Died"},
|
| + {name:"CANCELED", human:"Canceled"},
|
| + {name:"COMPLETED_SUCCESS", human:"Completed (Success)"},
|
| + {name:"COMPLETED_FAILURE", human:"Completed (Failure)"},
|
| + {name:"DEDUPED", human:"Deduplicated"},
|
| + {name:"EXPIRED", human:"Expired"},
|
| + {name:"PENDING", human:"Pending"},
|
| + {name:"RUNNING", human:"Running"},
|
| + {name:"TIMED_OUT", human:"Timed Out"},
|
| + ];
|
| + Polymer({
|
| + is: 'task-list-summary',
|
| +
|
| + behaviors: [SwarmingBehaviors.CommonBehavior],
|
| +
|
| + properties: {
|
| + auth_headers: {
|
| + type: Object,
|
| + },
|
| + busy: {
|
| + type: Boolean,
|
| + computed: "_anyBusy(_busyArr1.*,_busyArr2.*,_busy3)",
|
| + notify: true,
|
| + },
|
| + count_params: {
|
| + type: Object,
|
| + },
|
| + columns: {
|
| + type: Array,
|
| + },
|
| + num_tasks: {
|
| + type: Number,
|
| + },
|
| + sort: {
|
| + type: String,
|
| + },
|
| +
|
| + _busyArr1: {
|
| + type:Array,
|
| + value: function() {
|
| + return [];
|
| + }
|
| + },
|
| + _busyArr2: {
|
| + type:Array,
|
| + value: function() {
|
| + return [];
|
| + }
|
| + },
|
| + _busy3: {
|
| + type: Boolean,
|
| + value: false,
|
| + },
|
| + _all_counts: {
|
| + type: Array,
|
| + value: function() {
|
| + return [];
|
| + }
|
| + },
|
| + _all_summary: {
|
| + type: Array,
|
| + value: function() {
|
| + return ALL_TASKS_SUMMARY;
|
| + }
|
| + },
|
| + _selected_counts: {
|
| + type: Array,
|
| + value: function() {
|
| + return [];
|
| + }
|
| + },
|
| + _selected_exact: {
|
| + type: Object,
|
| + },
|
| + _selected_summary: {
|
| + type: Array,
|
| + value: function() {
|
| + return SELECTED_TASKS_SUMMARY;
|
| + }
|
| + },
|
| +
|
| + },
|
| +
|
| + observers: [
|
| + "_recountEverything(auth_headers.*,count_params.*)"
|
| + ],
|
| +
|
| + // Returns true if any of the busy signals are true.
|
| + _anyBusy: function() {
|
| + for (var i = 0; i<this._busyArr1.length; i++) {
|
| + if (this._busyArr1[i].status) {
|
| + return true;
|
| + }
|
| + }
|
| + for (var i = 0; i<this._busyArr2.length; i++) {
|
| + if (this._busyArr2[i].status) {
|
| + return true;
|
| + }
|
| + }
|
| + return this._busy3;
|
| + },
|
| +
|
| + // Returns the idx'th count of obj.
|
| + _idx: function(obj, idx) {
|
| + return obj && obj[idx] && obj[idx].count;
|
| + },
|
| +
|
| + // Recount all the task counts. This will make use of _getJsonAsyncArr because
|
| + // the results will be generated in a dom-repeat.
|
| + _recountEverything: function() {
|
| + if (!this.auth_headers || !this.count_params) {
|
| + return;
|
| + }
|
| + // convert to seconds because API uses seconds.
|
| + var now = (new Date()).getTime()/1000;
|
| + var last2Days = now - 24 * 60 * 60;
|
| +
|
| + // TODO(kjlubick): Once users can specify their own times, respect those limits here.
|
| +
|
| + var queryObj = {
|
| + start: [last2Days],
|
| + };
|
| +
|
| + for (var i = 0; i < ALL_TASKS_SUMMARY.length; i++) {
|
| + if (this._all_counts.length < ALL_TASKS_SUMMARY.length) {
|
| + this.push("_all_counts", {});
|
| + }
|
| + queryObj.state = [ALL_TASKS_SUMMARY[i].name];
|
| + this._getJsonAsyncArr(i, "_all_counts","/api/swarming/v1/tasks/count","_busyArr1",
|
| + this.auth_headers, queryObj);
|
| + }
|
| +
|
| + queryObj = JSON.parse(JSON.stringify(this.count_params));
|
| + queryObj.start = [last2Days];
|
| + this._getJsonAsync("_selected_exact","/api/swarming/v1/tasks/count","_busy3",
|
| + this.auth_headers, queryObj);
|
| +
|
| + for (var j = 0; j < SELECTED_TASKS_SUMMARY.length; j++) {
|
| + if (this._selected_counts.length < SELECTED_TASKS_SUMMARY.length) {
|
| + this.push("_selected_counts", {});
|
| + }
|
| + queryObj.state = [SELECTED_TASKS_SUMMARY[j].name];
|
| + this._getJsonAsyncArr(j, "_selected_counts","/api/swarming/v1/tasks/count","_busyArr2",
|
| + this.auth_headers, queryObj);
|
| + }
|
| + },
|
| +
|
| + // _makeURL creates a task-list url that keeps the columns and sort requirements the same
|
| + // while changing which state is represented. The preserveOthers signifies if other
|
| + // filtering parameters (e.g. tags) should be kept as well.
|
| + _makeURL: function(state, preserveOthers) {
|
| + var fstr = "state:"+state;
|
| + if (preserveOthers) {
|
| + var fstr = encodeURIComponent(fstr);
|
| + var url = window.location.href;
|
| + if (url.indexOf(fstr+"&") !== -1) {
|
| + // The state filter is already on the list.
|
| + return undefined;
|
| + }
|
| + if (url.indexOf("f=state") === -1) {
|
| + return url + "&f=" + fstr;
|
| + }
|
| + // Things can't be in multiple states at once - so replace it.
|
| + // %3A is url encoded colon (:)
|
| + return url.replace(/f=state%3A[A-Z_]+/, `f=state%3A${fstr}`);
|
| + }
|
| + var params = {
|
| + s: [this.sort],
|
| + c: this.columns,
|
| + }
|
| + if (state) {
|
| + params["f"] = [fstr];
|
| + }
|
| +
|
| + return window.location.href.split('?')[0] + '?' + sk.query.fromParamSet(params);
|
| + },
|
| +
|
| + });
|
| + })();
|
| + </script>
|
| +</dom-module>
|
|
|