| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | |
| 4 that can be found in the LICENSE file. | |
| 5 | |
| 6 This in an HTML Import-able file that contains the definition | |
| 7 of the following elements: | |
| 8 | |
| 9 <bot-list-data> | |
| 10 | |
| 11 This makes calls authenticated with Oauth 2 to the swarming apis. It parses | |
| 12 that data into usable data structures. | |
| 13 | |
| 14 Usage: | |
| 15 | |
| 16 <bot-list-data></bot-list-data> | |
| 17 | |
| 18 Properties: | |
| 19 // inputs | |
| 20 auth_headers: Object, the OAuth2 header to include in the request. This | |
| 21 should come from swarming-app. | |
| 22 query_params: Object, The query params that will filter the query | |
| 23 server-side. This can have dimensions:Array<String>, quarantined:String | |
| 24 and is_dead: String. For example: | |
| 25 { | |
| 26 "dimensions": ["pool:Skia", "device_type:sprout"], | |
| 27 "quarantined": "FALSE", // optional | |
| 28 "is_dead": "TRUE", // optional | |
| 29 } | |
| 30 For a full list of dimensions in the fleet, see the API call: | |
| 31 https://[swarming_url]/_ah/api/swarming/v1/bots/dimensions | |
| 32 // outputs | |
| 33 tasks: Array<Object>, all tasks returned by the server. | |
| 34 | |
| 35 Methods: | |
| 36 signIn(): Force a signin of the user using OAuth. This happens | |
| 37 automatically when auth_headers is set. | |
| 38 | |
| 39 Events: | |
| 40 None. | |
| 41 --> | |
| 42 | |
| 43 <link rel="import" href="/res/imp/common/common-behavior.html"> | |
| 44 <link rel="import" href="/res/imp/common/task-behavior.html"> | |
| 45 | |
| 46 <dom-module id="task-list-data"> | |
| 47 <script> | |
| 48 (function(){ | |
| 49 var TIMES = ["abandoned_ts", "completed_ts", "created_ts", "modified_ts", "s
tarted_ts"]; | |
| 50 Polymer({ | |
| 51 is: 'task-list-data', | |
| 52 | |
| 53 behaviors: [ | |
| 54 SwarmingBehaviors.CommonBehavior, | |
| 55 SwarmingBehaviors.TaskBehavior, | |
| 56 ], | |
| 57 | |
| 58 properties: { | |
| 59 // inputs | |
| 60 auth_headers: { | |
| 61 type: Object, | |
| 62 observer: "signIn", | |
| 63 }, | |
| 64 query_params: { | |
| 65 type: Object, | |
| 66 }, | |
| 67 tasks: { | |
| 68 type: Array, | |
| 69 }, | |
| 70 | |
| 71 // outputs | |
| 72 busy: { | |
| 73 type: Boolean, | |
| 74 computed: "_or(_busy2,_busy1)", | |
| 75 notify: true, | |
| 76 }, | |
| 77 primary_map: { | |
| 78 type: Object, | |
| 79 computed: "_primaryMap(_tags,_dimensions,tasks.*)", | |
| 80 notify: true, | |
| 81 }, | |
| 82 primary_arr: { | |
| 83 type: Array, | |
| 84 computed: "_primaryArr(primary_map)", | |
| 85 notify: true, | |
| 86 }, | |
| 87 | |
| 88 | |
| 89 // private | |
| 90 _busy2: { | |
| 91 type: Boolean, | |
| 92 value: false | |
| 93 }, | |
| 94 _busy1: { | |
| 95 type: Boolean, | |
| 96 value: false | |
| 97 }, | |
| 98 _dimensions: { | |
| 99 type: Object, | |
| 100 }, | |
| 101 _list: { | |
| 102 type: Object, | |
| 103 }, | |
| 104 _tags: { | |
| 105 type: Object, | |
| 106 }, | |
| 107 }, | |
| 108 | |
| 109 signIn: function(){ | |
| 110 this._getJsonAsync("_tags", "/_ah/api/swarming/v1/tasks/tags", | |
| 111 "_busy2", this.auth_headers); | |
| 112 this._getJsonAsync("_dimensions","/_ah/api/swarming/v1/bots/dimensions", | |
| 113 "_busy1", this.auth_headers); | |
| 114 }, | |
| 115 | |
| 116 _primaryArr: function(map) { | |
| 117 var arr = Object.keys(map); | |
| 118 arr.sort(); | |
| 119 return arr; | |
| 120 }, | |
| 121 | |
| 122 _primaryMap: function(tags, dims) { | |
| 123 tags = (tags && tags.tasks_tags) || []; | |
| 124 dims = (dims && dims.bots_dimensions) || []; | |
| 125 tasks = this.tasks || []; | |
| 126 var map = {}; | |
| 127 // We combine all the tags reported by the tags endpoint, all known | |
| 128 // dimensions from the dimensions endpoint, and the tags seen in the | |
| 129 // returned tasks, just in case they didn't show up in the first two. | |
| 130 // This way a user can filter by what the data actually has and can | |
| 131 // discover new tags to filter by. | |
| 132 tags.forEach(function(t) { | |
| 133 if (!map[t.key]) { | |
| 134 map[t.key] = {}; | |
| 135 } | |
| 136 var values = t.value || []; | |
| 137 values.forEach(function(v) { | |
| 138 map[t.key][v] = true; | |
| 139 }) | |
| 140 }); | |
| 141 | |
| 142 dims.forEach(function(d) { | |
| 143 var vals = d.value; | |
| 144 if (!map[d.key]) { | |
| 145 map[d.key] = {}; | |
| 146 } | |
| 147 vals.forEach(function(v) { | |
| 148 map[d.key][v] = true; | |
| 149 }) | |
| 150 }); | |
| 151 | |
| 152 tasks.forEach(function(t) { | |
| 153 Object.keys(t.tagMap).forEach(function(k) { | |
| 154 var v = t.tagMap[k]; | |
| 155 if (!map[k]) { | |
| 156 map[k] = {}; | |
| 157 } | |
| 158 map[k][v] = true; | |
| 159 }); | |
| 160 }); | |
| 161 | |
| 162 delete map["user"][""]; | |
| 163 map["user"]["none"] = true; | |
| 164 | |
| 165 // Turn the Map<Object,Map<Boolean>> into a Map<Object,Array<String>> | |
| 166 // with all of the aliases applied. | |
| 167 var pMap = {}; | |
| 168 for (key in map) { | |
| 169 var values = Object.keys(map[key]); | |
| 170 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(key) === -1) { | |
| 171 pMap[key] = values; | |
| 172 } else { | |
| 173 var aliased = []; | |
| 174 values.forEach(function(value){ | |
| 175 aliased.push(swarming.alias.apply(value, key)); | |
| 176 }); | |
| 177 pMap[key] = aliased; | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 // Custom filter options | |
| 182 pMap["name"] = []; | |
| 183 // Some of these are hard coded because the server expects something | |
| 184 // like "DEDUPED" instead of the more human friendly | |
| 185 // "COMPLETED (DEDUPED)" | |
| 186 pMap["state"] = [this.PENDING, this.RUNNING, "PENDING_RUNNING", this.COM
PLETED, | |
| 187 "COMPLETED_SUCCESS", "COMPLETED_FAILURE", this.EXPIRED, this.TIMED_O
UT, | |
| 188 this.BOT_DIED, this.CANCELED, "DEDUPED", "ALL"]; | |
| 189 pMap["costs_usd"] = []; | |
| 190 pMap["deduped_from"] = []; | |
| 191 pMap["duration"] = []; | |
| 192 pMap["server_versions"] = []; | |
| 193 | |
| 194 // TODO(kjlubick): Allow a person to sort on the task list by bot | |
| 195 pMap["bot"] = []; | |
| 196 TIMES.forEach(function(t) { | |
| 197 pMap[t] = []; | |
| 198 }); | |
| 199 | |
| 200 return pMap; | |
| 201 }, | |
| 202 | |
| 203 parseTasks: function(json) { | |
| 204 if (!json|| !json.items) { | |
| 205 return []; | |
| 206 } | |
| 207 var now = new Date(); | |
| 208 | |
| 209 // Do any preprocessing here | |
| 210 json.items.forEach(function(t) { | |
| 211 var tagMap = {}; | |
| 212 t.tags = t.tags || []; | |
| 213 t.tags.forEach(function(tag) { | |
| 214 var split = tag.split(":", 1) | |
| 215 var key = split[0]; | |
| 216 var rest = tag.substring(key.length + 1); | |
| 217 tagMap[key] = rest; | |
| 218 }); | |
| 219 t.tagMap = tagMap; | |
| 220 | |
| 221 TIMES.forEach(function(time) { | |
| 222 if (t[time]) { | |
| 223 t[time] = new Date(t[time]); | |
| 224 t["human_"+time] = sk.human.localeTime(t[time]); | |
| 225 } | |
| 226 }); | |
| 227 // Running tasks have no duration set, so we can figure it out. | |
| 228 if (!t.duration && t.state === this.RUNNING && t.started_ts){ | |
| 229 t.duration = (now - t.started_ts) / 1000; | |
| 230 } | |
| 231 // Make the duration human readable | |
| 232 if (t.duration){ | |
| 233 t.human_duration = this._humanDuration(t.duration); | |
| 234 } | |
| 235 }.bind(this)); | |
| 236 return json.items; | |
| 237 } | |
| 238 }); | |
| 239 })(); | |
| 240 </script> | |
| 241 </dom-module> | |
| OLD | NEW |