| OLD | NEW |
| 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 <bot-list> | 9 <bot-list> |
| 10 | 10 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 } | 49 } |
| 50 .dead { | 50 .dead { |
| 51 background-color: #cccccc; | 51 background-color: #cccccc; |
| 52 } | 52 } |
| 53 .bot-list th > span { | 53 .bot-list th > span { |
| 54 /* Leave space for sort-toggle*/ | 54 /* Leave space for sort-toggle*/ |
| 55 padding-right: 30px; | 55 padding-right: 30px; |
| 56 } | 56 } |
| 57 </style> | 57 </style> |
| 58 | 58 |
| 59 <url-param name="sort" | 59 <url-param name="s" |
| 60 value="{{_sortstr}}" | 60 value="{{_sortstr}}" |
| 61 default_value="id:asc"> | 61 default_value="id:asc"> |
| 62 </url-param> | 62 </url-param> |
| 63 | 63 |
| 64 <swarming-app | 64 <swarming-app |
| 65 client_id="[[client_id]]" | 65 client_id="[[client_id]]" |
| 66 auth_headers="{{_auth_headers}}" | 66 auth_headers="{{_auth_headers}}" |
| 67 signed_in="{{_signed_in}}" | 67 signed_in="{{_signed_in}}" |
| 68 | 68 |
| 69 busy="[[_busy]]" | 69 busy="[[_busy]]" |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 </template> <!--bot-table repeat--> | 205 </template> <!--bot-table repeat--> |
| 206 </tbody> | 206 </tbody> |
| 207 </table> | 207 </table> |
| 208 </div> | 208 </div> |
| 209 | 209 |
| 210 </swarming-app> | 210 </swarming-app> |
| 211 | 211 |
| 212 </template> | 212 </template> |
| 213 <script> | 213 <script> |
| 214 (function(){ | 214 (function(){ |
| 215 var UNKNOWN = "unknown"; |
| 215 // see dynamic-table for more information on specialColumns, headerMap, | 216 // see dynamic-table for more information on specialColumns, headerMap, |
| 216 // columnMap, and specialSort | 217 // columnMap, and specialSort |
| 217 var specialColumns = ["id", "task"]; | 218 var specialColumns = ["id", "task"]; |
| 218 | 219 |
| 219 var headerMap = { | 220 var headerMap = { |
| 220 // "id" and "task" are special, so they don't go here. They have their | 221 // "id" and "task" are special, so they don't go here. They have their |
| 221 // headers hard-coded above. | 222 // headers hard-coded above. |
| 222 "android_devices": "Android Devices", | 223 "android_devices": "Android Devices", |
| 223 "cores": "Cores", | 224 "cores": "Cores", |
| 224 "cpu": "CPU", | 225 "cpu": "CPU", |
| 225 "device": "Non-android Device", | 226 "device": "Non-android Device", |
| 226 "device_os": "Device OS", | 227 "device_os": "Device OS", |
| 227 "device_type": "Device Type", | 228 "device_type": "Device Type", |
| 228 "disk_space": "Free Space (MB)", | 229 "disk_space": "Free Space (MB)", |
| 229 "gpu": "GPU", | 230 "gpu": "GPU", |
| 230 "os": "OS", | 231 "os": "OS", |
| 231 "pool": "Pool", | 232 "pool": "Pool", |
| 232 "status": "Status", | 233 "status": "Status", |
| 233 "xcode_version": "XCode Version", | 234 "xcode_version": "XCode Version", |
| 235 "battery_health": "Battery Health", |
| 236 "battery_level": "Battery Level (%)", |
| 237 "battery_status": "Battery Status", |
| 238 "battery_temperature": "Battery Temp (°C)", |
| 239 "battery_voltage": "Battery Voltage (mV)", |
| 240 "bot_temperature": "Bot Temp (°C)", |
| 241 "device_temperature": "Device Temp (°C)", |
| 234 }; | 242 }; |
| 235 | 243 |
| 236 var columnMap = { | 244 var columnMap = { |
| 237 android_devices: function(bot) { | 245 android_devices: function(bot) { |
| 238 var devs = this._attribute(bot, "android_devices", "0"); | 246 var devs = this._attribute(bot, "android_devices", "0"); |
| 239 if (this._verbose) { | 247 if (this._verbose) { |
| 240 return devs.join(" | ") + " devices available"; | 248 return devs.join(" | ") + " devices available"; |
| 241 } | 249 } |
| 242 // max() works on strings as long as they can be coerced to Number. | 250 // max() works on strings as long as they can be coerced to Number. |
| 243 return Math.max(...devs) + " devices available"; | 251 return Math.max(...devs) + " devices available"; |
| 244 }, | 252 }, |
| 253 battery_health: function(){ |
| 254 return ""; |
| 255 }, |
| 256 battery_level: function(){ |
| 257 return ""; |
| 258 }, |
| 259 battery_status: function(){ |
| 260 return ""; |
| 261 }, |
| 262 battery_temperature: function(){ |
| 263 return ""; |
| 264 }, |
| 265 battery_voltage: function(){ |
| 266 return ""; |
| 267 }, |
| 268 bot_temperature: function(bot){ |
| 269 if (this._verbose) { |
| 270 return bot.state.temp.zones || UNKNOWN; |
| 271 } |
| 272 return bot.state.temp.average || UNKNOWN; |
| 273 }, |
| 274 device_temperature: function(){ |
| 275 return ""; |
| 276 }, |
| 245 disk_space: function(bot) { | 277 disk_space: function(bot) { |
| 246 var aliased = []; | 278 var aliased = []; |
| 247 bot.disks.forEach(function(disk){ | 279 bot.disks.forEach(function(disk){ |
| 248 var alias = sk.human.bytes(disk.mb, swarming.MB); | 280 var alias = sk.human.bytes(disk.mb, swarming.MB); |
| 249 aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias)); | 281 aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias)); |
| 250 }.bind(this)); | 282 }.bind(this)); |
| 251 if (this._verbose) { | 283 if (this._verbose) { |
| 252 return aliased.join(" | "); | 284 return aliased.join(" | "); |
| 253 } | 285 } |
| 254 return aliased[0]; | 286 return aliased[0]; |
| 255 }, | 287 }, |
| 288 |
| 289 external_ip: function(bot) { |
| 290 return bot.external_ip || "none"; |
| 291 }, |
| 292 first_seen: function(bot) { |
| 293 return sk.human.localeTime(bot.first_seen_ts) |
| 294 }, |
| 256 id: function(bot) { | 295 id: function(bot) { |
| 257 return bot.bot_id; | 296 return bot.bot_id; |
| 258 }, | 297 }, |
| 298 last_seen: function(bot) { |
| 299 if (this._verbose) { |
| 300 return sk.human.localeTime(bot.last_seen_ts); |
| 301 } |
| 302 return this._timeDiffApprox(bot.last_seen_ts) + " ago"; |
| 303 }, |
| 259 status: function(bot) { | 304 status: function(bot) { |
| 260 // If a bot is both dead and quarantined, show the deadness over the | 305 // If a bot is both dead and quarantined, show the deadness over the |
| 261 // quarentinedness. | 306 // quarentinedness. |
| 262 if (bot.is_dead) { | 307 if (bot.is_dead) { |
| 263 return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) + | 308 return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) + |
| 264 " ago"; | 309 " ago"; |
| 265 } | 310 } |
| 266 if (bot.quarantined) { | 311 if (bot.quarantined) { |
| 267 var msg = this._state(bot, "quarantined")[0]; | 312 var msg = this._state(bot, "quarantined")[0]; |
| 268 // Sometimes, the quarantined message is actually in "error". This | 313 // Sometimes, the quarantined message is actually in "error". This |
| 269 // happens when the bot code has thrown an exception. | 314 // happens when the bot code has thrown an exception. |
| 270 if (msg === "unknown" || msg === "true" || msg === true) { | 315 if (msg === UNKNOWN || msg === "true" || msg === true) { |
| 271 msg = this._attribute(bot, "error"); | 316 msg = this._attribute(bot, "error"); |
| 272 } | 317 } |
| 273 return "Quarantined: " + msg; | 318 return "Quarantined: " + msg; |
| 274 } | 319 } |
| 275 return "Alive"; | 320 return "Alive"; |
| 276 }, | 321 }, |
| 277 task: function(bot){ | 322 task: function(bot) { |
| 278 return this._taskId(bot); | 323 return this._taskId(bot); |
| 279 }, | 324 }, |
| 325 version: function(bot) { |
| 326 var v = bot.version || UNKNOWN |
| 327 return v.substring(0, 10); |
| 328 } |
| 280 }; | 329 }; |
| 281 | 330 |
| 282 var deviceColumnMap = { | 331 var deviceColumnMap = { |
| 283 android_devices: function(device) { | 332 android_devices: function(device) { |
| 284 var str = this._androidAliasDevice(device); | 333 var str = this._androidAliasDevice(device); |
| 285 if (device.okay) { | 334 if (device.okay) { |
| 286 str = swarming.alias.apply(this._deviceType(device), str); | 335 str = swarming.alias.apply(this._deviceType(device), str); |
| 287 } | 336 } |
| 288 str += " S/N:"; | 337 str += " S/N:"; |
| 289 str += device.serial; | 338 str += device.serial; |
| 290 return str; | 339 return str; |
| 291 }, | 340 }, |
| 341 battery_health: function(device){ |
| 342 var h = (device.battery && device.battery.health) || UNKNOWN; |
| 343 return swarming.alias.apply(h, "battery_health"); |
| 344 }, |
| 345 battery_level: function(device){ |
| 346 return (device.battery && device.battery.level) || UNKNOWN; |
| 347 }, |
| 348 battery_status: function(device){ |
| 349 var s = (device.battery && device.battery.status) || UNKNOWN; |
| 350 return swarming.alias.apply(s, "battery_status"); |
| 351 }, |
| 352 battery_temperature: function(device){ |
| 353 // Battery temps are in tenths of degrees C - convert to more human rang
e. |
| 354 return (device.battery && device.battery.temperature / 10) || UNKNOWN |
| 355 }, |
| 356 battery_voltage: function(device){ |
| 357 return (device.battery && device.battery.voltage) || UNKNOWN; |
| 358 }, |
| 359 device_temperature: function(device){ |
| 360 if (this._verbose) { |
| 361 return device.temp.zones || UNKNOWN; |
| 362 } |
| 363 return device.temp.average || UNKNOWN; |
| 364 }, |
| 292 device_os: function(device) { | 365 device_os: function(device) { |
| 293 if (device.build) { | 366 if (device.build) { |
| 294 return device.build["build.id"]; | 367 return device.build["build.id"]; |
| 295 } | 368 } |
| 296 return "unknown"; | 369 return UNKNOWN; |
| 297 }, | 370 }, |
| 298 status: function(device) { | 371 status: function(device) { |
| 299 return device.state; | 372 return device.state; |
| 300 } | 373 } |
| 301 } | 374 } |
| 302 | 375 |
| 376 |
| 377 function deviceAverage(col) { |
| 378 return function(dir, botA, botB) { |
| 379 // sort by average of all devices or 0 if no devices. |
| 380 var avgA = 0; |
| 381 var avgB = 0; |
| 382 var devsA = this._devices(botA); |
| 383 devsA.forEach(function(device) { |
| 384 var v = deviceColumnMap[col](device); |
| 385 v = parseFloat(swarming.alias.unapply(v)) || 0; |
| 386 avgA += v / devsA.length; |
| 387 }.bind(this)); |
| 388 var devsB = this._devices(botB); |
| 389 devsB.forEach(function(device) { |
| 390 var v = deviceColumnMap[col](device); |
| 391 v = parseFloat(swarming.alias.unapply(v)) || 0; |
| 392 avgB += v / devsB.length; |
| 393 }.bind(this)); |
| 394 return dir * swarming.naturalCompare(avgA, avgB); |
| 395 }; |
| 396 } |
| 397 |
| 303 var specialSort = { | 398 var specialSort = { |
| 304 android_devices: function(dir, botA, botB) { | 399 android_devices: function(dir, botA, botB) { |
| 305 // We sort on the number of attached devices. Note that this | 400 // We sort on the number of attached devices. Note that this |
| 306 // may not be the same as android_devices, because _devices().length | 401 // may not be the same as android_devices, because _devices().length |
| 307 // counts all devices plugged into the bot, whereas android_devices | 402 // counts all devices plugged into the bot, whereas android_devices |
| 308 // counts just devices ready for work. | 403 // counts just devices ready for work. |
| 309 var botACol = this._devices(botA).length; | 404 var botACol = this._devices(botA).length; |
| 310 var botBCol = this._devices(botB).length; | 405 var botBCol = this._devices(botB).length; |
| 311 return dir * swarming.naturalCompare(botACol, botBCol); | 406 return dir * swarming.naturalCompare(botACol, botBCol); |
| 312 }, | 407 }, |
| 408 |
| 409 battery_health: deviceAverage("battery_health"), |
| 410 battery_level: deviceAverage("battery_level"), |
| 411 battery_status: deviceAverage("battery_status"), |
| 412 battery_temperature: deviceAverage("battery_temperature"), |
| 413 battery_voltage: deviceAverage("battery_voltage"), |
| 414 device_temperature: deviceAverage("device_temperature"), |
| 415 |
| 416 bot_temperature: function(dir, botA, botB) { |
| 417 // Sort by average temperature. |
| 418 var botACol = botA.state.temp.average || 0; |
| 419 var botBCol = botB.state.temp.average || 0; |
| 420 return dir * swarming.naturalCompare(botACol, botBCol); |
| 421 }, |
| 313 disk_space: function(dir, botA, botB) { | 422 disk_space: function(dir, botA, botB) { |
| 314 // We sort based on the raw number of MB of the first disk. | 423 // We sort based on the raw number of MB of the first disk. |
| 315 var botACol = botA.disks[0].mb; | 424 var botACol = botA.disks[0].mb; |
| 316 var botBCol = botB.disks[0].mb;; | 425 var botBCol = botB.disks[0].mb; |
| 317 return dir * swarming.naturalCompare(botACol, botBCol); | 426 return dir * swarming.naturalCompare(botACol, botBCol); |
| 318 }, | 427 }, |
| 428 first_seen: function(dir, botA, botB) { |
| 429 var botACol = botA.first_seen_ts; |
| 430 var botBCol = botB.first_seen_ts; |
| 431 return dir * swarming.naturalCompare(botACol, botBCol) |
| 432 }, |
| 433 last_seen: function(dir, botA, botB) { |
| 434 var botACol = botA.last_seen_ts; |
| 435 var botBCol = botB.last_seen_ts; |
| 436 return dir * swarming.naturalCompare(botACol, botBCol) |
| 437 } |
| 319 }; | 438 }; |
| 320 | 439 |
| 321 Polymer({ | 440 Polymer({ |
| 322 is: 'bot-list', | 441 is: 'bot-list', |
| 323 | 442 |
| 324 // The order behaviors are applied in matters - later ones overwrite | 443 // The order behaviors are applied in matters - later ones overwrite |
| 325 // attributes of earlier ones | 444 // attributes of earlier ones |
| 326 behaviors: [ | 445 behaviors: [ |
| 327 SwarmingBehaviors.BotListBehavior, | 446 SwarmingBehaviors.BotListBehavior, |
| 328 SwarmingBehaviors.DynamicTableBehavior, | 447 SwarmingBehaviors.DynamicTableBehavior, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 if (!device.okay) { | 507 if (!device.okay) { |
| 389 return "bad-device"; | 508 return "bad-device"; |
| 390 } | 509 } |
| 391 return ""; | 510 return ""; |
| 392 }, | 511 }, |
| 393 | 512 |
| 394 }); | 513 }); |
| 395 })(); | 514 })(); |
| 396 </script> | 515 </script> |
| 397 </dom-module> | 516 </dom-module> |
| OLD | NEW |