| 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> | |
| 10 | |
| 11 bot-list creats a dynamic table for viewing swarming bots. Columns can be | |
| 12 dynamically filtered and it supports client-side filtering. | |
| 13 | |
| 14 This is a top-level element. | |
| 15 | |
| 16 Properties: | |
| 17 client_id: String, Oauth 2.0 client id. It will be set by server-side | |
| 18 template evaluation. | |
| 19 | |
| 20 Methods: | |
| 21 None. | |
| 22 | |
| 23 Events: | |
| 24 None. | |
| 25 --> | |
| 26 | |
| 27 <link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-la
yout-classes.html"> | |
| 28 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> | |
| 29 | |
| 30 <link rel="import" href="/res/imp/common/dynamic-table-behavior.html"> | |
| 31 <link rel="import" href="/res/imp/common/error-toast.html"> | |
| 32 <link rel="import" href="/res/imp/common/sort-toggle.html"> | |
| 33 <link rel="import" href="/res/imp/common/swarming-app.html"> | |
| 34 <link rel="import" href="/res/imp/common/url-param.html"> | |
| 35 <link rel="import" href="/res/imp/common/pageable-data.html"> | |
| 36 | |
| 37 <link rel="import" href="bot-filters.html"> | |
| 38 <link rel="import" href="bot-list-data.html"> | |
| 39 <link rel="import" href="bot-list-shared-behavior.html"> | |
| 40 <link rel="import" href="bot-list-summary.html"> | |
| 41 | |
| 42 <dom-module id="bot-list"> | |
| 43 <template> | |
| 44 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-
style dynamic-table-style"> | |
| 45 bot-filters, bot-list-summary { | |
| 46 margin-bottom: 8px; | |
| 47 margin-right: 10px; | |
| 48 } | |
| 49 .quarantined, .bad-device { | |
| 50 background-color: #ffdddd; | |
| 51 } | |
| 52 .dead { | |
| 53 background-color: #cccccc; | |
| 54 } | |
| 55 .bot-list th > span { | |
| 56 /* Leave space for sort-toggle*/ | |
| 57 padding-right: 30px; | |
| 58 } | |
| 59 </style> | |
| 60 | |
| 61 <url-param name="s" | |
| 62 value="{{_sortstr}}" | |
| 63 default_value="id:asc"> | |
| 64 </url-param> | |
| 65 | |
| 66 <swarming-app | |
| 67 client_id="[[client_id]]" | |
| 68 auth_headers="{{_auth_headers}}" | |
| 69 signed_in="{{_signed_in}}" | |
| 70 server_details="{{_server_details}}" | |
| 71 | |
| 72 busy="[[_or(_busy1,_busy2)]]" | |
| 73 name="Swarming Bot List"> | |
| 74 | |
| 75 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> | |
| 76 | |
| 77 <div hidden$="[[_not(_signed_in)]]"> | |
| 78 | |
| 79 <div class="horizontal layout"> | |
| 80 | |
| 81 <bot-filters | |
| 82 dimensions="[[_dimensions]]" | |
| 83 primary_map="[[_primary_map]]" | |
| 84 primary_arr="[[_primary_arr]]" | |
| 85 | |
| 86 columns="{{_columns}}" | |
| 87 query_params="{{_query_params}}" | |
| 88 filter="{{_filter}}" | |
| 89 verbose="{{_verbose}}"> | |
| 90 </bot-filters> | |
| 91 | |
| 92 <bot-list-summary | |
| 93 columns="[[_columns]]" | |
| 94 fleet="[[_fleet]]" | |
| 95 filtered_bots="[[_filteredSortedItems]]" | |
| 96 sort="[[_sortstr]]" | |
| 97 verbose="[[_verbose]]"> | |
| 98 </bot-list-summary> | |
| 99 | |
| 100 </div> | |
| 101 | |
| 102 <bot-list-data | |
| 103 id="data" | |
| 104 auth_headers="[[_auth_headers]]" | |
| 105 query_params="[[_query_params]]" | |
| 106 | |
| 107 busy="{{_busy1}}" | |
| 108 dimensions="{{_dimensions}}" | |
| 109 fleet="{{_fleet}}" | |
| 110 primary_map="{{_primary_map}}" | |
| 111 primary_arr="{{_primary_arr}}"> | |
| 112 </bot-list-data> | |
| 113 | |
| 114 <table class="bot-list"> | |
| 115 <thead on-sort_change="_sortChange"> | |
| 116 <!-- To allow for dynamic columns without having a lot of copy-pasted | |
| 117 code, we break columns up into "special" and "plain" columns. Special | |
| 118 columns require some sort of HTML output (e.g. anchor tags) and plain | |
| 119 columns just output text. The plain columns use Polymer functions to | |
| 120 insert their text [_header(), _column(), _deviceColumn()]. Polymer | |
| 121 functions do not allow HTML (to avoid XSS), so special columns, like i
d | |
| 122 and task are inserted in a fixed order. | |
| 123 --> | |
| 124 <tr> | |
| 125 <th> | |
| 126 <span>Bot Id</span> | |
| 127 <sort-toggle | |
| 128 name="id" | |
| 129 current="[[_sort]]"> | |
| 130 </sort-toggle> | |
| 131 </th> | |
| 132 <!-- This wonky syntax is the proper way to listen to changes on a
n | |
| 133 array (we are listening to all subproperties). The element returne
d is | |
| 134 not of much use, so we'll ignore it in _hide() and use this._colum
ns. | |
| 135 --> | |
| 136 <th hidden$="[[_hide('cloud_console_link', _columns.*)]]"> | |
| 137 <span>Bot in Cloud Console</span> | |
| 138 <sort-toggle | |
| 139 name="cloud_console_link" | |
| 140 current="[[_sort]]"> | |
| 141 </sort-toggle> | |
| 142 </th> | |
| 143 <th hidden$="[[_hide('mp_lease_id', _columns.*)]]"> | |
| 144 <span>Machine Provider Lease Id</span> | |
| 145 <sort-toggle | |
| 146 name="mp_lease_id" | |
| 147 current="[[_sort]]"> | |
| 148 </sort-toggle> | |
| 149 </th> | |
| 150 <th hidden$="[[_hide('task', _columns.*)]]"> | |
| 151 <span>Current Task</span> | |
| 152 <sort-toggle | |
| 153 name="task" | |
| 154 current="[[_sort]]"> | |
| 155 </sort-toggle> | |
| 156 </th> | |
| 157 | |
| 158 <template | |
| 159 is="dom-repeat" | |
| 160 items="[[_plainColumns]]" | |
| 161 as="c"> | |
| 162 <th hidden$="[[_hide(c)]]"> | |
| 163 <span>[[_header(c)]]</span> | |
| 164 <sort-toggle | |
| 165 name="[[c]]" | |
| 166 current="[[_sort]]"> | |
| 167 </sort-toggle> | |
| 168 </th> | |
| 169 </template> | |
| 170 </tr> | |
| 171 </thead> | |
| 172 <tbody> | |
| 173 <template | |
| 174 id="bot_table" | |
| 175 is="dom-repeat" | |
| 176 items="[[_filteredSortedItems]]" | |
| 177 as="bot" | |
| 178 initial-count=50> | |
| 179 | |
| 180 <tr class$="[[_botClass(bot)]]"> | |
| 181 <td> | |
| 182 <a | |
| 183 class="center" | |
| 184 href$="[[_botLink(bot.bot_id)]]" | |
| 185 target="_blank" | |
| 186 rel="noopener"> | |
| 187 [[bot.bot_id]] | |
| 188 </a> | |
| 189 </td> | |
| 190 <td hidden$="[[_hide('cloud_console_link', _columns.*)]]"> | |
| 191 <a href$="[[_ccLink(bot)]]">[[_ccText(bot)]]</a> | |
| 192 </td> | |
| 193 <td hidden$="[[_hide('mp_lease_id', _columns.*)]]"> | |
| 194 <a href$="[[_mpLink(bot, _server_details.machine_provider_temp
late)]]"> | |
| 195 [[_column('mp_lease_id', bot,_verbose)]] | |
| 196 </a> | |
| 197 </td> | |
| 198 <td hidden$="[[_hide('task', _columns.*)]]"> | |
| 199 <a href$="[[_taskLink(bot.task_id)]]">[[_taskId(bot)]]</a> | |
| 200 </td> | |
| 201 | |
| 202 <template | |
| 203 is="dom-repeat" | |
| 204 items="[[_plainColumns]]" | |
| 205 as="c"> | |
| 206 <td hidden$="[[_hide(c)]]"> | |
| 207 [[_column(c, bot, _verbose)]] | |
| 208 </td> | |
| 209 </template> | |
| 210 | |
| 211 </tr> | |
| 212 <template | |
| 213 is="dom-repeat" | |
| 214 items="[[_devices(bot)]]" | |
| 215 as="device"> | |
| 216 <tr | |
| 217 hidden$="[[_hide('android_devices', _columns.*)]]" | |
| 218 class$="[[_deviceClass(device)]]"> | |
| 219 <td></td> | |
| 220 <td hidden$="[[_hide('task', _columns.*)]]"></td> | |
| 221 <template | |
| 222 is="dom-repeat" | |
| 223 items="[[_plainColumns]]" | |
| 224 as="c"> | |
| 225 <td hidden$="[[_hide(c)]]"> | |
| 226 [[_deviceColumn(c, device, _verbose)]] | |
| 227 </td> | |
| 228 </template> | |
| 229 </tr> | |
| 230 </template> <!--devices repeat--> | |
| 231 </template> <!--bot-table repeat--> | |
| 232 </tbody> | |
| 233 </table> | |
| 234 <pageable-data | |
| 235 id="page_bots" | |
| 236 busy="{{_busy2}}" | |
| 237 label="Show more bots" | |
| 238 output="{{_items}}" | |
| 239 parse="[[_parseBots]]"> | |
| 240 </pageable-data> | |
| 241 </div> | |
| 242 | |
| 243 <error-toast></error-toast> | |
| 244 </swarming-app> | |
| 245 | |
| 246 </template> | |
| 247 <script> | |
| 248 (function(){ | |
| 249 var UNKNOWN = "unknown"; | |
| 250 // see dynamic-table for more information on specialColumns, headerMap, | |
| 251 // columnMap, and specialSort | |
| 252 var specialColumns = ["id", "task", "cloud_console_link", "mp_lease_id"]; | |
| 253 | |
| 254 var headerMap = { | |
| 255 // "id" and "task" are special, so they don't go here. They have their | |
| 256 // headers hard-coded above. | |
| 257 "android_devices": "Android Devices", | |
| 258 "battery_health": "Battery Health", | |
| 259 "battery_level": "Battery Level (%)", | |
| 260 "battery_status": "Battery Status", | |
| 261 "battery_temperature": "Battery Temp (°C)", | |
| 262 "battery_voltage": "Battery Voltage (mV)", | |
| 263 "bot_temperature": "Bot Temp (°C)", | |
| 264 "cores": "Cores", | |
| 265 "cpu": "CPU", | |
| 266 "device": "Non-android Device", | |
| 267 "device_os": "Device OS", | |
| 268 "device_temperature": "Device Temp (°C)", | |
| 269 "device_type": "Device Type", | |
| 270 "disk_space": "Free Space (MB)", | |
| 271 "first_seen": "First Seen", | |
| 272 "gpu": "GPU", | |
| 273 "last_seen": "Last Seen", | |
| 274 "mp_lease_expires": "Machine Provider Lease Expires", | |
| 275 "os": "OS", | |
| 276 "pool": "Pool", | |
| 277 "running_time": "Swarming Uptime", | |
| 278 "status": "Status", | |
| 279 "uptime": "Bot Uptime", | |
| 280 "xcode_version": "XCode Version", | |
| 281 }; | |
| 282 | |
| 283 var columnMap = { | |
| 284 android_devices: function(bot) { | |
| 285 var devs = this._attribute(bot, "android_devices", "0"); | |
| 286 if (this._verbose) { | |
| 287 return devs.join(" | ") + " devices available"; | |
| 288 } | |
| 289 // max() works on strings as long as they can be coerced to Number. | |
| 290 return Math.max(...devs) + " devices available"; | |
| 291 }, | |
| 292 battery_health: function(){ | |
| 293 return ""; | |
| 294 }, | |
| 295 battery_level: function(){ | |
| 296 return ""; | |
| 297 }, | |
| 298 battery_status: function(){ | |
| 299 return ""; | |
| 300 }, | |
| 301 battery_temperature: function(){ | |
| 302 return ""; | |
| 303 }, | |
| 304 battery_voltage: function(){ | |
| 305 return ""; | |
| 306 }, | |
| 307 bot_temperature: function(bot){ | |
| 308 if (this._verbose) { | |
| 309 return bot.state.temp.zones || UNKNOWN; | |
| 310 } | |
| 311 return bot.state.temp.average || UNKNOWN; | |
| 312 }, | |
| 313 device_temperature: function(){ | |
| 314 return ""; | |
| 315 }, | |
| 316 disk_space: function(bot) { | |
| 317 var aliased = []; | |
| 318 bot.disks.forEach(function(disk){ | |
| 319 var alias = sk.human.bytes(disk.mb, sk.MB); | |
| 320 aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias)); | |
| 321 }.bind(this)); | |
| 322 if (this._verbose) { | |
| 323 return aliased.join(" | "); | |
| 324 } | |
| 325 return aliased[0]; | |
| 326 }, | |
| 327 external_ip: function(bot) { | |
| 328 return bot.external_ip || "none"; | |
| 329 }, | |
| 330 first_seen: function(bot) { | |
| 331 return sk.human.localeTime(bot.first_seen_ts) | |
| 332 }, | |
| 333 id: function(bot) { | |
| 334 return bot.bot_id; | |
| 335 }, | |
| 336 last_seen: function(bot) { | |
| 337 if (this._verbose) { | |
| 338 return sk.human.localeTime(bot.last_seen_ts); | |
| 339 } | |
| 340 return this._timeDiffApprox(bot.last_seen_ts) + " ago"; | |
| 341 }, | |
| 342 mp_lease_id: function(bot) { | |
| 343 var id = bot.lease_id || "none"; | |
| 344 if (this._verbose) { | |
| 345 return id; | |
| 346 } | |
| 347 return id.substring(0, 10); | |
| 348 }, | |
| 349 mp_lease_expires: function(bot) { | |
| 350 if (!bot.lease_expiration_ts) { | |
| 351 return "N/A"; | |
| 352 } | |
| 353 if (this._verbose) { | |
| 354 return sk.human.localeTime(bot.lease_expiration_ts); | |
| 355 } | |
| 356 if (bot.lease_expiration_ts < new Date()) { | |
| 357 return this._timeDiffApprox(bot.lease_expiration_ts) + " ago"; | |
| 358 } | |
| 359 return "in " + this._timeDiffApprox(bot.lease_expiration_ts); | |
| 360 }, | |
| 361 running_time: function(bot) { | |
| 362 var u = this._state(bot, "running_time"); | |
| 363 if (!u) { | |
| 364 return "unknown"; | |
| 365 } | |
| 366 return sk.human.strDuration(u); | |
| 367 }, | |
| 368 status: function(bot) { | |
| 369 // If a bot is both dead and quarantined, show the deadness over the | |
| 370 // quarentinedness. | |
| 371 if (bot.is_dead) { | |
| 372 return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) + | |
| 373 " ago"; | |
| 374 } | |
| 375 if (bot.quarantined) { | |
| 376 var msg = this._state(bot, "quarantined")[0]; | |
| 377 // Sometimes, the quarantined message is actually in "error". This | |
| 378 // happens when the bot code has thrown an exception. | |
| 379 if (msg === UNKNOWN || msg === "true" || msg === true) { | |
| 380 msg = this._attribute(bot, "error"); | |
| 381 } | |
| 382 return "Quarantined: " + msg; | |
| 383 } | |
| 384 return "Alive"; | |
| 385 }, | |
| 386 task: function(bot) { | |
| 387 return this._taskId(bot); | |
| 388 }, | |
| 389 uptime: function(bot) { | |
| 390 var u = this._state(bot, "uptime"); | |
| 391 if (!u) { | |
| 392 return "unknown"; | |
| 393 } | |
| 394 return sk.human.strDuration(u); | |
| 395 }, | |
| 396 version: function(bot) { | |
| 397 var v = bot.version || UNKNOWN | |
| 398 return v.substring(0, 10); | |
| 399 } | |
| 400 }; | |
| 401 | |
| 402 var deviceColumnMap = { | |
| 403 android_devices: function(device) { | |
| 404 var str = this._androidAliasDevice(device); | |
| 405 if (device.okay) { | |
| 406 str = swarming.alias.apply(this._deviceType(device), str); | |
| 407 } | |
| 408 str += " S/N:"; | |
| 409 str += device.serial; | |
| 410 return str; | |
| 411 }, | |
| 412 battery_health: function(device){ | |
| 413 var h = (device.battery && device.battery.health) || UNKNOWN; | |
| 414 return swarming.alias.apply(h, "battery_health"); | |
| 415 }, | |
| 416 battery_level: function(device){ | |
| 417 return (device.battery && device.battery.level) || UNKNOWN; | |
| 418 }, | |
| 419 battery_status: function(device){ | |
| 420 var s = (device.battery && device.battery.status) || UNKNOWN; | |
| 421 return swarming.alias.apply(s, "battery_status"); | |
| 422 }, | |
| 423 battery_temperature: function(device){ | |
| 424 // Battery temps are in tenths of degrees C - convert to more human rang
e. | |
| 425 return (device.battery && device.battery.temperature / 10) || UNKNOWN | |
| 426 }, | |
| 427 battery_voltage: function(device){ | |
| 428 return (device.battery && device.battery.voltage) || UNKNOWN; | |
| 429 }, | |
| 430 device_temperature: function(device){ | |
| 431 if (this._verbose) { | |
| 432 return device.temp.zones || UNKNOWN; | |
| 433 } | |
| 434 return device.temp.average || UNKNOWN; | |
| 435 }, | |
| 436 device_os: function(device) { | |
| 437 if (device.build) { | |
| 438 return device.build["build.id"]; | |
| 439 } | |
| 440 return UNKNOWN; | |
| 441 }, | |
| 442 status: function(device) { | |
| 443 return device.state; | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 | |
| 448 function deviceAverage(col) { | |
| 449 return function(dir, botA, botB) { | |
| 450 // sort by average of all devices or 0 if no devices. | |
| 451 var avgA = 0; | |
| 452 var avgB = 0; | |
| 453 var devsA = this._devices(botA); | |
| 454 devsA.forEach(function(device) { | |
| 455 var v = deviceColumnMap[col](device); | |
| 456 v = parseFloat(swarming.alias.unapply(v)) || 0; | |
| 457 avgA += v / devsA.length; | |
| 458 }.bind(this)); | |
| 459 var devsB = this._devices(botB); | |
| 460 devsB.forEach(function(device) { | |
| 461 var v = deviceColumnMap[col](device); | |
| 462 v = parseFloat(swarming.alias.unapply(v)) || 0; | |
| 463 avgB += v / devsB.length; | |
| 464 }.bind(this)); | |
| 465 return dir * swarming.naturalCompare(avgA, avgB); | |
| 466 }; | |
| 467 } | |
| 468 | |
| 469 var specialSort = { | |
| 470 android_devices: function(dir, botA, botB) { | |
| 471 // We sort on the number of attached devices. Note that this | |
| 472 // may not be the same as android_devices, because _devices().length | |
| 473 // counts all devices plugged into the bot, whereas android_devices | |
| 474 // counts just devices ready for work. | |
| 475 var botACol = this._devices(botA).length; | |
| 476 var botBCol = this._devices(botB).length; | |
| 477 return dir * swarming.naturalCompare(botACol, botBCol); | |
| 478 }, | |
| 479 | |
| 480 battery_health: deviceAverage("battery_health"), | |
| 481 battery_level: deviceAverage("battery_level"), | |
| 482 battery_status: deviceAverage("battery_status"), | |
| 483 battery_temperature: deviceAverage("battery_temperature"), | |
| 484 battery_voltage: deviceAverage("battery_voltage"), | |
| 485 device_temperature: deviceAverage("device_temperature"), | |
| 486 | |
| 487 bot_temperature: function(dir, botA, botB) { | |
| 488 // Sort by average temperature. | |
| 489 var botACol = botA.state.temp.average || 0; | |
| 490 var botBCol = botB.state.temp.average || 0; | |
| 491 return dir * swarming.naturalCompare(botACol, botBCol); | |
| 492 }, | |
| 493 disk_space: function(dir, botA, botB) { | |
| 494 // We sort based on the raw number of MB of the first disk. | |
| 495 var botACol = botA.disks[0].mb; | |
| 496 var botBCol = botB.disks[0].mb; | |
| 497 return dir * swarming.naturalCompare(botACol, botBCol); | |
| 498 }, | |
| 499 first_seen: function(dir, botA, botB) { | |
| 500 var botACol = botA.first_seen_ts; | |
| 501 var botBCol = botB.first_seen_ts; | |
| 502 return dir * swarming.naturalCompare(botACol, botBCol) | |
| 503 }, | |
| 504 last_seen: function(dir, botA, botB) { | |
| 505 var botACol = botA.last_seen_ts; | |
| 506 var botBCol = botB.last_seen_ts; | |
| 507 return dir * swarming.naturalCompare(botACol, botBCol) | |
| 508 }, | |
| 509 running_time: function(dir, botA, botB) { | |
| 510 var botACol = this._state(botA, "running_time") || 0; | |
| 511 var botBCol = this._state(botB, "running_time") || 0; | |
| 512 return dir * swarming.naturalCompare(botACol, botBCol) | |
| 513 }, | |
| 514 uptime: function(dir, botA, botB) { | |
| 515 var botACol = this._state(botA, "uptime") || 0; | |
| 516 var botBCol = this._state(botB, "uptime") || 0; | |
| 517 return dir * swarming.naturalCompare(botACol, botBCol) | |
| 518 }, | |
| 519 }; | |
| 520 | |
| 521 Polymer({ | |
| 522 is: 'bot-list', | |
| 523 | |
| 524 // The order behaviors are applied in matters - later ones overwrite | |
| 525 // attributes of earlier ones | |
| 526 behaviors: [ | |
| 527 SwarmingBehaviors.BotListBehavior, | |
| 528 SwarmingBehaviors.DynamicTableBehavior, | |
| 529 ], | |
| 530 | |
| 531 properties: { | |
| 532 client_id: { | |
| 533 type: String, | |
| 534 }, | |
| 535 | |
| 536 _busy1: { | |
| 537 type: Boolean, | |
| 538 value: false | |
| 539 }, | |
| 540 _busy2: { | |
| 541 type: Boolean, | |
| 542 value: false | |
| 543 }, | |
| 544 _parseBots: { | |
| 545 type: Function, | |
| 546 value: function() { | |
| 547 return this.$.data.parseBots.bind(this); | |
| 548 } | |
| 549 }, | |
| 550 | |
| 551 // For dynamic table. | |
| 552 _columnMap: { | |
| 553 type: Object, | |
| 554 value: function() { | |
| 555 var base = this._commonColumns(); | |
| 556 for (var attr in columnMap) { | |
| 557 base[attr] = columnMap[attr]; | |
| 558 } | |
| 559 return base; | |
| 560 }, | |
| 561 }, | |
| 562 _headerMap: { | |
| 563 type: Object, | |
| 564 value: headerMap, | |
| 565 }, | |
| 566 _specialColumns: { | |
| 567 type: Array, | |
| 568 value: specialColumns, | |
| 569 }, | |
| 570 _specialSort: { | |
| 571 type: Object, | |
| 572 value: specialSort, | |
| 573 }, | |
| 574 }, | |
| 575 | |
| 576 observers:["_reload(_query_params,_auth_headers)"], | |
| 577 | |
| 578 _androidAliasDevice: function(device) { | |
| 579 if (device.notReady) { | |
| 580 return UNAUTHENTICATED.toUpperCase(); | |
| 581 } | |
| 582 return swarming.alias.android(this._deviceType(device)); | |
| 583 }, | |
| 584 | |
| 585 _botClass: function(bot) { | |
| 586 if (bot.is_dead) { | |
| 587 return "dead"; | |
| 588 } | |
| 589 if (bot.quarantined) { | |
| 590 return "quarantined"; | |
| 591 } | |
| 592 return ""; | |
| 593 }, | |
| 594 | |
| 595 _ccLink: function(bot){ | |
| 596 var z = this._attribute(bot, "zone")[0]; | |
| 597 if (z === "unknown") { | |
| 598 return undefined; | |
| 599 } | |
| 600 return this._cloudConsoleLink(z, bot.bot_id); | |
| 601 }, | |
| 602 | |
| 603 _ccText: function(bot){ | |
| 604 var z = this._attribute(bot, "zone")[0]; | |
| 605 if (z === "unknown") { | |
| 606 return "Not on GCE"; | |
| 607 } | |
| 608 return "View Bot"; | |
| 609 }, | |
| 610 | |
| 611 _deviceColumn: function(col, device) { | |
| 612 var f = deviceColumnMap[col]; | |
| 613 if (!f || !device) { | |
| 614 return ""; | |
| 615 } | |
| 616 return f.bind(this)(device); | |
| 617 }, | |
| 618 | |
| 619 _deviceClass: function(device) { | |
| 620 if (!device.okay) { | |
| 621 return "bad-device"; | |
| 622 } | |
| 623 return ""; | |
| 624 }, | |
| 625 | |
| 626 _mpLink: function(bot, template) { | |
| 627 if (!bot || !bot.lease_id || !template) { | |
| 628 return false; | |
| 629 } | |
| 630 return template.replace("%s", bot.lease_id); | |
| 631 }, | |
| 632 | |
| 633 _reload: function() { | |
| 634 if (!this._auth_headers || !this._query_params) { | |
| 635 return; | |
| 636 } | |
| 637 var url = "/_ah/api/swarming/v1/bots/list?" + sk.query.fromParamSet(this
._query_params); | |
| 638 this.$.page_bots.load(url,this._auth_headers); | |
| 639 } | |
| 640 | |
| 641 }); | |
| 642 })(); | |
| 643 </script> | |
| 644 </dom-module> | |
| OLD | NEW |