| OLD | NEW |
| 1 <!DOCTYPE html><html><head><!-- | 1 <!DOCTYPE html><html><head><!-- |
| 2 @license | 2 @license |
| 3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved. | 3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved. |
| 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 7 Code distributed by Google as part of the polymer project is also | 7 Code distributed by Google as part of the polymer project is also |
| 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 9 --><!-- | 9 --><!-- |
| 10 @license | 10 @license |
| (...skipping 20536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 20547 <script> | 20547 <script> |
| 20548 Polymer({ | 20548 Polymer({ |
| 20549 is: 'paper-input', | 20549 is: 'paper-input', |
| 20550 | 20550 |
| 20551 behaviors: [ | 20551 behaviors: [ |
| 20552 Polymer.IronFormElementBehavior, | 20552 Polymer.IronFormElementBehavior, |
| 20553 Polymer.PaperInputBehavior | 20553 Polymer.PaperInputBehavior |
| 20554 ] | 20554 ] |
| 20555 }); | 20555 }); |
| 20556 </script> | 20556 </script> |
| 20557 <script> |
| 20558 |
| 20559 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; |
| 20560 (function(){ |
| 20561 var ANDROID_ALIASES = { |
| 20562 "bullhead": "Nexus 5X", |
| 20563 "flo": "Nexus 7", |
| 20564 "flounder": "Nexus 9", |
| 20565 "hammerhead": "Nexus 5", |
| 20566 "mako": "Nexus 4", |
| 20567 "shamu": "Nexus 6", |
| 20568 }; |
| 20569 // Taken from http://developer.android.com/reference/android/os/BatteryManag
er.html |
| 20570 var BATTERY_HEALTH_UNKNOWN = 1; |
| 20571 var BATTERY_HEALTH_GOOD = 2; |
| 20572 var BATTERY_STATUS_CHARGING = 2; |
| 20573 |
| 20574 var UNAUTHENTICATED = "unauthenticated"; |
| 20575 var AVAILABLE = "available"; |
| 20576 var UNKNOWN = "unknown"; |
| 20577 |
| 20578 var GPU_ALIASES = { |
| 20579 "1002": "AMD", |
| 20580 "1002:6779": "AMD Radeon HD 6450/7450/8450", |
| 20581 "1002:6821": "AMD Radeon HD 8870M", |
| 20582 "1002:9830": "AMD Radeon HD 8400", |
| 20583 "102b": "Matrox", |
| 20584 "102b:0522": "Matrox MGA G200e", |
| 20585 "102b:0532": "Matrox MGA G200eW", |
| 20586 "102b:0534": "Matrox G200eR2", |
| 20587 "10de": "NVIDIA", |
| 20588 "10de:08aa": "NVIDIA GeForce 320M", |
| 20589 "10de:0fe9": "NVIDIA GeForce GT 750M Mac Edition", |
| 20590 "10de:104a": "NVIDIA GeForce GT 610", |
| 20591 "10de:11c0": "NVIDIA GeForce GTX 660", |
| 20592 "10de:1244": "NVIDIA GeForce GTX 550 Ti", |
| 20593 "10de:1401": "NVIDIA GeForce GTX 960", |
| 20594 "8086": "Intel", |
| 20595 "8086:041a": "Intel Xeon Integrated", |
| 20596 "8086:0a2e": "Intel Haswell Integrated", |
| 20597 "8086:0d26": "Intel Crystal Well Integrated", |
| 20598 } |
| 20599 |
| 20600 // For consistency, all aliases are displayed like: |
| 20601 // Nexus 5X (bullhead) |
| 20602 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. |
| 20603 var ALIAS_REGEXP = /.+ \((.*)\)/; |
| 20604 |
| 20605 // This behavior wraps up all the shared bot-list functionality. |
| 20606 SwarmingBehaviors.BotListBehavior = { |
| 20607 |
| 20608 properties: { |
| 20609 // TODO(kjlubick): Add more of these things from state, as they |
| 20610 // needed/useful/requested. |
| 20611 DIMENSIONS: { |
| 20612 type: Array, |
| 20613 value: function(){ |
| 20614 return ["android_devices", "cores", "cpu", "device_type", |
| 20615 "device_os", "gpu", "id", "os", "pool"]; |
| 20616 }, |
| 20617 }, |
| 20618 DIMENSIONS_WITH_ALIASES: { |
| 20619 type: Array, |
| 20620 value: function(){ |
| 20621 return ["device_type", "gpu"]; |
| 20622 }, |
| 20623 }, |
| 20624 BOT_PROPERTIES: { |
| 20625 type: Array, |
| 20626 value: function() { |
| 20627 return ["disk_space", "task", "status"]; |
| 20628 } |
| 20629 }, |
| 20630 }, |
| 20631 |
| 20632 _androidAlias: function(dt) { |
| 20633 return ANDROID_ALIASES[dt] || UNKNOWN; |
| 20634 }, |
| 20635 |
| 20636 // _applyAlias is the consistent way to modify a string to show its alias. |
| 20637 _applyAlias: function(orig, alias) { |
| 20638 return alias +" ("+orig+")"; |
| 20639 }, |
| 20640 |
| 20641 // _attribute looks first in dimension and then in state for the |
| 20642 // specified attribute. This will always return an array. If there is |
| 20643 // no matching attribute, ["unknown"] will be returned. |
| 20644 _attribute: function(bot, attr, none) { |
| 20645 none = none || UNKNOWN; |
| 20646 return this._dimension(bot, attr) || this._state(bot, attr) || [none]; |
| 20647 }, |
| 20648 |
| 20649 _devices: function(bot) { |
| 20650 var devices = []; |
| 20651 var d = (bot && bot.state && bot.state.devices) || {}; |
| 20652 // state.devices is like {Serial:Object}, so we need to keep the serial |
| 20653 for (key in d) { |
| 20654 var o = d[key]; |
| 20655 o.serial = key; |
| 20656 o.okay = (o.state === AVAILABLE); |
| 20657 devices.push(o); |
| 20658 } |
| 20659 return devices; |
| 20660 }, |
| 20661 |
| 20662 // _deviceType returns the codename of a given Android device. |
| 20663 _deviceType: function(device) { |
| 20664 if (!device || !device.build) { |
| 20665 return UNKNOWN; |
| 20666 } |
| 20667 var t = device.build["build.product"] || device.build["product.board"] |
| |
| 20668 device.build["product.device"] || UNKNOWN; |
| 20669 return t.toLowerCase(); |
| 20670 }, |
| 20671 |
| 20672 // _dimension returns the given dimension of a bot. If it is defined, it |
| 20673 // is an array of strings. |
| 20674 _dimension: function(bot, dim) { |
| 20675 if (!bot || !bot.dimensions || !dim) { |
| 20676 return undefined; |
| 20677 } |
| 20678 for (var i = 0; i < bot.dimensions.length; i++) { |
| 20679 if (bot.dimensions[i].key === dim) { |
| 20680 return bot.dimensions[i].value; |
| 20681 } |
| 20682 } |
| 20683 return undefined; |
| 20684 }, |
| 20685 |
| 20686 _gpuAlias: function(gpu) { |
| 20687 return GPU_ALIASES[gpu] || UNKNOWN; |
| 20688 }, |
| 20689 |
| 20690 _not: function(a) { |
| 20691 return !a; |
| 20692 }, |
| 20693 |
| 20694 _or: function() { |
| 20695 var result = false; |
| 20696 // can't use .foreach, as arguments isn't really a function. |
| 20697 for (var i = 0; i < arguments.length; i++) { |
| 20698 result = result || arguments[i]; |
| 20699 } |
| 20700 return result; |
| 20701 }, |
| 20702 |
| 20703 // _state returns the requested attribute from a bot's state. |
| 20704 // For consistency with _dimension, if the attribute is not an array, |
| 20705 // it is put as the only element in an array. |
| 20706 _state: function(bot, attr) { |
| 20707 if (!bot || !bot.state || !bot.state[attr]) { |
| 20708 return undefined |
| 20709 } |
| 20710 var state = bot.state[attr]; |
| 20711 if (Array.isArray(state)) { |
| 20712 return state; |
| 20713 } |
| 20714 return [state]; |
| 20715 }, |
| 20716 |
| 20717 _taskId: function(bot) { |
| 20718 if (bot && bot.task_id) { |
| 20719 return bot.task_id; |
| 20720 } |
| 20721 return "idle"; |
| 20722 }, |
| 20723 |
| 20724 // _unalias will return the base dimension/state with its alias removed |
| 20725 // if it had one. This is handy for sorting and filtering. |
| 20726 _unalias: function(str) { |
| 20727 var match = ALIAS_REGEXP.exec(str); |
| 20728 if (match) { |
| 20729 return match[1]; |
| 20730 } |
| 20731 return str; |
| 20732 }, |
| 20733 } |
| 20734 })() |
| 20735 </script> |
| 20557 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> | 20736 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> |
| 20558 <template> | 20737 <template> |
| 20559 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning"> | 20738 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning"> |
| 20560 :host { | 20739 :host { |
| 20561 display: block; | 20740 display: block; |
| 20562 font-family: sans-serif; | 20741 font-family: sans-serif; |
| 20563 } | 20742 } |
| 20564 #filter { | 20743 #filter { |
| 20565 margin:0 5px; | 20744 margin:0 5px; |
| 20566 } | 20745 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 20685 </div> | 20864 </div> |
| 20686 | 20865 |
| 20687 <paper-checkbox checked="{{verbose}}">Verbose Entries</paper-checkbox> | 20866 <paper-checkbox checked="{{verbose}}">Verbose Entries</paper-checkbox> |
| 20688 </div> | 20867 </div> |
| 20689 | 20868 |
| 20690 </div> | 20869 </div> |
| 20691 | 20870 |
| 20692 </template> | 20871 </template> |
| 20693 <script> | 20872 <script> |
| 20694 (function(){ | 20873 (function(){ |
| 20695 var FILTER_SEP = " | "; | 20874 var FILTER_SEP = ":"; |
| 20696 // filterMap is a map of primary -> function. The function returns a | 20875 // filterMap is a map of primary -> function. The function returns a |
| 20697 // boolean "does the bot (first arg) match the second argument". These | 20876 // boolean "does the bot (first arg) match the second argument". These |
| 20698 // functions will have "this" be the botlist, and will have access to all | 20877 // functions will have "this" be the botlist, and will have access to all |
| 20699 // functions defined in bot-list and bot-list-shared. | 20878 // functions defined in bot-list and bot-list-shared. |
| 20700 var filterMap = { | 20879 var filterMap = { |
| 20701 cores: function(bot, cores){ | 20880 android_devices: function(bot, num) { |
| 20702 var o = this._cores(bot); | 20881 var o = this._attribute(bot, "android_devices", "0"); |
| 20882 return o.indexOf(num) !== -1; |
| 20883 }, |
| 20884 cores: function(bot, cores) { |
| 20885 var o = this._attribute(bot, "cores"); |
| 20703 return o.indexOf(cores) !== -1; | 20886 return o.indexOf(cores) !== -1; |
| 20704 }, | 20887 }, |
| 20705 cpu: function(bot, cpu){ | 20888 cpu: function(bot, cpu) { |
| 20706 var o = this._dimension(bot, "cpu") || ["none"]; | 20889 var o = this._attribute(bot, "cpu"); |
| 20707 return o.indexOf(cpu) !== -1; | 20890 return o.indexOf(cpu) !== -1; |
| 20708 }, | 20891 }, |
| 20709 devices: function(bot, device){ | 20892 device_os: function(bot, os) { |
| 20710 if (device === "none") { | 20893 var o = this._attribute(bot, "device_os", "none"); |
| 20711 return this._devices(bot).length === 0; | 20894 return o.indexOf(os) !== -1; |
| 20712 } | |
| 20713 // extract the deviceType, if it is not "unknown". | |
| 20714 device = this._unalias(device); | |
| 20715 var found = false; | |
| 20716 this._devices(bot).forEach(function(d) { | |
| 20717 if (this._deviceType(d) === device) { | |
| 20718 found = true; | |
| 20719 } | |
| 20720 }.bind(this)); | |
| 20721 return found; | |
| 20722 }, | 20895 }, |
| 20723 gpu: function(bot, gpu){ | 20896 device_type: function(bot, dt) { |
| 20724 var o = this._dimension(bot, "gpu") || ["none"]; | 20897 var o = this._attribute(bot, "device_type", "none"); |
| 20898 return o.indexOf(this._unalias(dt)) !== -1; |
| 20899 }, |
| 20900 disk_space: function(bot, space) { |
| 20901 return true; |
| 20902 }, |
| 20903 gpu: function(bot, gpu) { |
| 20904 var o = this._attribute(bot, "gpu", "none"); |
| 20725 return o.indexOf(this._unalias(gpu)) !== -1; | 20905 return o.indexOf(this._unalias(gpu)) !== -1; |
| 20726 }, | 20906 }, |
| 20727 id: function(bot, id) { | 20907 id: function(bot, id) { |
| 20728 return bot.bot_id === id; | 20908 return true; |
| 20729 }, | 20909 }, |
| 20730 os: function(bot, os){ | 20910 os: function(bot, os) { |
| 20731 var o = this._dimension(bot, "os") || ["Unknown"]; | 20911 var o = this._attribute(bot, "os"); |
| 20732 return o.indexOf(os) !== -1; | 20912 return o.indexOf(os) !== -1; |
| 20733 }, | 20913 }, |
| 20734 pool: function(bot, pool){ | 20914 pool: function(bot, pool) { |
| 20735 var o = this._dimension(bot, "pool") || ["Unknown"]; | 20915 var o = this._attribute(bot, "pool"); |
| 20736 return o.indexOf(pool) !== -1; | 20916 return o.indexOf(pool) !== -1; |
| 20737 }, | 20917 }, |
| 20738 status: function(bot, status){ | 20918 status: function(bot, status) { |
| 20739 if (status === "quarantined") { | 20919 if (status === "quarantined") { |
| 20740 return bot.quarantined; | 20920 return bot.quarantined; |
| 20741 } else if (status === "dead") { | 20921 } else if (status === "dead") { |
| 20742 return bot.is_dead; | 20922 return bot.is_dead; |
| 20743 } else { | 20923 } else { |
| 20744 // Status must be "available". | 20924 // Status must be "available". |
| 20745 return !bot.quarantined && !bot.is_dead; | 20925 return !bot.quarantined && !bot.is_dead; |
| 20746 } | 20926 } |
| 20747 }, | 20927 }, |
| 20748 task: function(bot, task) { | 20928 task: function(bot, task) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 20781 }; | 20961 }; |
| 20782 } | 20962 } |
| 20783 } | 20963 } |
| 20784 return { | 20964 return { |
| 20785 idx: -1, | 20965 idx: -1, |
| 20786 }; | 20966 }; |
| 20787 }; | 20967 }; |
| 20788 | 20968 |
| 20789 Polymer({ | 20969 Polymer({ |
| 20790 is: "bot-filters", | 20970 is: "bot-filters", |
| 20971 |
| 20972 behaviors: [SwarmingBehaviors.BotListBehavior], |
| 20973 |
| 20791 properties: { | 20974 properties: { |
| 20792 // input | 20975 // input |
| 20793 primary_map: { | 20976 primary_map: { |
| 20794 type: Object, | 20977 type: Object, |
| 20795 }, | 20978 }, |
| 20796 primary_arr: { | 20979 primary_arr: { |
| 20797 type: Array, | 20980 type: Array, |
| 20798 }, | 20981 }, |
| 20799 | 20982 |
| 20800 // output | 20983 // output |
| 20801 columns: { | 20984 columns: { |
| 20802 type: Array, | 20985 type: Array, |
| 20803 value: function() { | 20986 value: function() { |
| 20804 // TODO(kjlubick) back these up to URL params and load them from | 20987 // TODO(kjlubick) back these up to URL params and load them from |
| 20805 // there on reload. | 20988 // there on reload. |
| 20806 return ["id","os","task","status"]; | 20989 return ["id","os","task","status"]; |
| 20807 }, | 20990 }, |
| 20808 notify: true, | 20991 notify: true, |
| 20809 }, | 20992 }, |
| 20993 dimensions: { |
| 20994 type: Array, |
| 20995 computed: "_extractDimensions(DIMENSIONS.*,_filters.*)", |
| 20996 notify: true, |
| 20997 }, |
| 20810 filter: { | 20998 filter: { |
| 20811 type: Object, | 20999 type: Object, |
| 20812 computed: "_makeFilter(_filters.*)", | 21000 computed: "_makeFilter(_filters.*)", |
| 20813 notify: true, | 21001 notify: true, |
| 20814 }, | 21002 }, |
| 20815 verbose: { | 21003 verbose: { |
| 20816 type: Boolean, | 21004 type: Boolean, |
| 20817 value: false, | 21005 value: false, |
| 20818 notify: true, | 21006 notify: true, |
| 20819 }, | 21007 }, |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 21025 }, | 21213 }, |
| 21026 | 21214 |
| 21027 _afterBold: function(item, query) { | 21215 _afterBold: function(item, query) { |
| 21028 var match = matchPartCaseInsensitive(item, query); | 21216 var match = matchPartCaseInsensitive(item, query); |
| 21029 if (match.idx === -1) { | 21217 if (match.idx === -1) { |
| 21030 return ""; | 21218 return ""; |
| 21031 } | 21219 } |
| 21032 return item.substring(match.idx + match.part.length); | 21220 return item.substring(match.idx + match.part.length); |
| 21033 }, | 21221 }, |
| 21034 | 21222 |
| 21223 _extractDimensions: function() { |
| 21224 var dims = [] |
| 21225 this._filters.forEach(function(f) { |
| 21226 var split = f.split(FILTER_SEP, 1) |
| 21227 var col = split[0]; |
| 21228 if (this.DIMENSIONS.indexOf(col) !== -1) { |
| 21229 var rest = f.substring(col.length + FILTER_SEP.length); |
| 21230 dims.push(col + FILTER_SEP + this._unalias(rest)) |
| 21231 }; |
| 21232 }.bind(this)); |
| 21233 return dims; |
| 21234 } |
| 21235 |
| 21035 }); | 21236 }); |
| 21036 })(); | 21237 })(); |
| 21037 </script> | 21238 </script> |
| 21038 </dom-module><script> | 21239 </dom-module><dom-module id="bot-list-data" assetpath="/res/imp/botlist/"> |
| 21039 | |
| 21040 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; | |
| 21041 (function(){ | |
| 21042 var ANDROID_ALIASES = { | |
| 21043 "bullhead": "Nexus 5X", | |
| 21044 "flo": "Nexus 7", | |
| 21045 "hammerhead": "Nexus 5", | |
| 21046 "mako": "Nexus 4", | |
| 21047 "shamu": "Nexus 6", | |
| 21048 }; | |
| 21049 // Taken from http://developer.android.com/reference/android/os/BatteryManag
er.html | |
| 21050 var BATTERY_HEALTH_UNKNOWN = 1; | |
| 21051 var BATTERY_HEALTH_GOOD = 2; | |
| 21052 var BATTERY_STATUS_CHARGING = 2; | |
| 21053 | |
| 21054 var UNAUTHENTICATED = "unauthenticated"; | |
| 21055 var AVAILABLE = "available"; | |
| 21056 | |
| 21057 var GPU_ALIASES = { | |
| 21058 "1002": "AMD", | |
| 21059 "1002:6779": "AMD Radeon HD 6450/7450/8450", | |
| 21060 "1002:6821": "AMD Radeon HD 8870M", | |
| 21061 "102b": "Matrox", | |
| 21062 "102b:0522": "Matrox MGA G200e", | |
| 21063 "102b:0532": "Matrox MGA G200eW", | |
| 21064 "102b:0534": "Matrox G200eR2", | |
| 21065 "10de": "NVIDIA", | |
| 21066 "10de:08aa": "NVIDIA GeForce 320M", | |
| 21067 "10de:0fe9": "NVIDIA GeForce GT 750M Mac Edition", | |
| 21068 "10de:104a": "NVIDIA GeForce GT 610", | |
| 21069 "10de:11c0": "NVIDIA GeForce GTX 660", | |
| 21070 "10de:1244": "NVIDIA GeForce GTX 550 Ti", | |
| 21071 "10de:1401": "NVIDIA GeForce GTX 960", | |
| 21072 "8086": "Intel", | |
| 21073 "8086:041a": "Intel Xeon Integrated", | |
| 21074 "8086:0a2e": "Intel Haswell Integrated", | |
| 21075 "8086:0d26": "Intel Crystal Well Integrated", | |
| 21076 } | |
| 21077 | |
| 21078 // For consistency, all aliases are displayed like: | |
| 21079 // Nexus 5X (bullhead) | |
| 21080 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. | |
| 21081 var ALIAS_REGEXP = /.+ \((.*)\)/; | |
| 21082 | |
| 21083 // This behavior wraps up all the shared bot-list functionality. | |
| 21084 SwarmingBehaviors.BotListBehavior = { | |
| 21085 | |
| 21086 _androidAlias: function(device) { | |
| 21087 if (device.notReady) { | |
| 21088 return UNAUTHENTICATED.toUpperCase(); | |
| 21089 } | |
| 21090 var t = this._deviceType(device); | |
| 21091 var a = ANDROID_ALIASES[t]; | |
| 21092 if (!a) { | |
| 21093 return "UNKNOWN"; | |
| 21094 } | |
| 21095 return a; | |
| 21096 }, | |
| 21097 | |
| 21098 // _applyAlias is the consistent way to modify a string to show its alias. | |
| 21099 _applyAlias: function(orig, alias) { | |
| 21100 return alias +" ("+orig+")"; | |
| 21101 }, | |
| 21102 | |
| 21103 _cores: function(bot) { | |
| 21104 // For whatever reason, sometimes cores are in dimensions and sometimes | |
| 21105 // they are in state, but never both. | |
| 21106 var c = (bot && bot.state && bot.state.cores); | |
| 21107 if (c && c.length > 0) { | |
| 21108 return c; | |
| 21109 } | |
| 21110 c = this._dimension(bot, "cores") || ["Unknown"]; | |
| 21111 return c; | |
| 21112 }, | |
| 21113 | |
| 21114 _devices: function(bot) { | |
| 21115 var devices = []; | |
| 21116 var d = (bot && bot.state && bot.state.devices) || {}; | |
| 21117 // state.devices is like {Serial:Object}, so we need to keep the serial | |
| 21118 for (key in d) { | |
| 21119 var o = d[key]; | |
| 21120 o.serial = key; | |
| 21121 o.okay = (o.state === AVAILABLE); | |
| 21122 devices.push(o); | |
| 21123 } | |
| 21124 return devices; | |
| 21125 }, | |
| 21126 | |
| 21127 // _deviceType returns the codename of a given Android device. | |
| 21128 _deviceType: function(device) { | |
| 21129 if (!device || !device.build) { | |
| 21130 return "unknown"; | |
| 21131 } | |
| 21132 var t = device.build["build.product"] || device.build["product.board"] |
| | |
| 21133 device.build["product.device"] || "unknown"; | |
| 21134 return t.toLowerCase(); | |
| 21135 }, | |
| 21136 | |
| 21137 // _dimension returns the given dimension of a bot. If it is defined, it | |
| 21138 // is typically an array of strings. | |
| 21139 _dimension: function(bot, dim) { | |
| 21140 if (!bot || !bot.dimensions || !dim) { | |
| 21141 return undefined; | |
| 21142 } | |
| 21143 for (var i = 0; i < bot.dimensions.length; i++) { | |
| 21144 if (bot.dimensions[i].key === dim) { | |
| 21145 return bot.dimensions[i].value; | |
| 21146 } | |
| 21147 } | |
| 21148 return undefined; | |
| 21149 }, | |
| 21150 | |
| 21151 _gpuAlias: function(gpu) { | |
| 21152 var a = GPU_ALIASES[gpu]; | |
| 21153 if (!a) { | |
| 21154 return "UNKNOWN"; | |
| 21155 } | |
| 21156 return a; | |
| 21157 }, | |
| 21158 | |
| 21159 _not: function(a) { | |
| 21160 return !a; | |
| 21161 }, | |
| 21162 | |
| 21163 _or: function() { | |
| 21164 var result = false; | |
| 21165 // can't use .foreach, as arguments isn't really a function. | |
| 21166 for (var i = 0; i < arguments.length; i++) { | |
| 21167 result = result || arguments[i]; | |
| 21168 } | |
| 21169 return result; | |
| 21170 }, | |
| 21171 | |
| 21172 _taskId: function(bot) { | |
| 21173 if (bot && bot.task_id) { | |
| 21174 return bot.task_id; | |
| 21175 } | |
| 21176 return "idle"; | |
| 21177 }, | |
| 21178 | |
| 21179 // _unalias will return the base dimension/state with its alias removed | |
| 21180 // if it had one. This is handy for sorting and filtering. | |
| 21181 _unalias: function(str) { | |
| 21182 var match = ALIAS_REGEXP.exec(str); | |
| 21183 if (match) { | |
| 21184 return match[1]; | |
| 21185 } | |
| 21186 return str; | |
| 21187 }, | |
| 21188 } | |
| 21189 })() | |
| 21190 </script> | |
| 21191 <dom-module id="bot-list-data" assetpath="/res/imp/botlist/"> | |
| 21192 <template> | 21240 <template> |
| 21193 <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth
_headers]]" handle-as="json" last-response="{{_list}}" loading="{{_busy1}}"> | 21241 <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth
_headers]]" params="[[_botlistParams(dimensions.*)]]" handle-as="json" last-resp
onse="{{_list}}" loading="{{_busy1}}"> |
| 21194 </iron-ajax> | 21242 </iron-ajax> |
| 21195 | 21243 |
| 21196 <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_
headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy2}}"> | 21244 <iron-ajax id="dimensions" url="/_ah/api/swarming/v1/bots/dimensions" header
s="[[auth_headers]]" handle-as="json" last-response="{{_dimensions}}" loading="{
{_busy2}}"> |
| 21245 </iron-ajax> |
| 21246 |
| 21247 <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_
headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy3}}"> |
| 21197 </iron-ajax> | 21248 </iron-ajax> |
| 21198 </template> | 21249 </template> |
| 21199 <script> | 21250 <script> |
| 21200 (function(){ | 21251 (function(){ |
| 21201 // TODO(kjlubick): Add more of these as well as things from state | 21252 |
| 21202 // i.e. disk space remaining. | |
| 21203 var DIMENSIONS = ["cores", "cpu", "id", "os", "pool"]; | |
| 21204 // "gpu" and "devices" are added separately because we need to | |
| 21205 // deal with aliases. | |
| 21206 var BOT_PROPERTIES = ["gpu", "devices", "task", "status"]; | |
| 21207 Polymer({ | 21253 Polymer({ |
| 21208 is: 'bot-list-data', | 21254 is: 'bot-list-data', |
| 21209 | 21255 |
| 21210 behaviors: [SwarmingBehaviors.BotListBehavior], | 21256 behaviors: [SwarmingBehaviors.BotListBehavior], |
| 21211 | 21257 |
| 21212 properties: { | 21258 properties: { |
| 21213 // inputs | 21259 // inputs |
| 21214 auth_headers: { | 21260 auth_headers: { |
| 21215 type: Object, | 21261 type: Object, |
| 21216 observer: "signIn", | 21262 observer: "signIn", |
| 21217 }, | 21263 }, |
| 21264 dimensions: { |
| 21265 type: Array, |
| 21266 }, |
| 21218 | 21267 |
| 21219 //outputs | 21268 //outputs |
| 21220 bots: { | 21269 bots: { |
| 21221 type: Array, | 21270 type: Array, |
| 21222 computed: "_bots(_list)", | 21271 computed: "_bots(_list)", |
| 21223 notify: true, | 21272 notify: true, |
| 21224 }, | 21273 }, |
| 21225 busy: { | 21274 busy: { |
| 21226 type: Boolean, | 21275 type: Boolean, |
| 21227 computed: "_or(_busy1,_busy2)", | 21276 computed: "_or(_busy1,_busy2,_busy3)", |
| 21228 notify: true, | 21277 notify: true, |
| 21229 }, | 21278 }, |
| 21230 fleet: { | 21279 fleet: { |
| 21231 type: Object, | 21280 type: Object, |
| 21232 computed: "_fleet(_count)", | 21281 computed: "_fleet(_count)", |
| 21233 notify: true, | 21282 notify: true, |
| 21234 }, | 21283 }, |
| 21235 primary_map: { | 21284 primary_map: { |
| 21236 type:Object, | 21285 type:Object, |
| 21237 computed: "_primaryMap(bots)", | 21286 computed: "_primaryMap(_dimensions)", |
| 21238 notify: true, | 21287 notify: true, |
| 21239 }, | 21288 }, |
| 21240 primary_arr: { | 21289 primary_arr: { |
| 21241 type:Array, | 21290 type: Array, |
| 21242 value: function() { | 21291 // DIMENSIONS and BOT_PROPERTIES are inherited from BotListBehavior |
| 21243 return DIMENSIONS.concat(BOT_PROPERTIES); | 21292 computed: "_primaryArr(DIMENSIONS, BOT_PROPERTIES)", |
| 21244 }, | |
| 21245 notify: true, | 21293 notify: true, |
| 21246 }, | 21294 }, |
| 21247 | 21295 |
| 21248 // private | 21296 // private |
| 21249 _count: { | 21297 _count: { |
| 21250 type: Object, | 21298 type: Object, |
| 21251 }, | 21299 }, |
| 21300 _dimensions: { |
| 21301 type: Object, |
| 21302 }, |
| 21252 _list: { | 21303 _list: { |
| 21253 type: Object, | 21304 type: Object, |
| 21254 }, | 21305 }, |
| 21255 }, | 21306 }, |
| 21256 | 21307 |
| 21257 signIn: function(){ | 21308 signIn: function(){ |
| 21258 this.$.botlist.generateRequest(); | 21309 this.$.botlist.auto = true; |
| 21259 this.$.fleet.generateRequest(); | 21310 this.$.dimensions.auto = true; |
| 21311 this.$.fleet.auto = true; |
| 21312 }, |
| 21313 |
| 21314 _botlistParams: function() { |
| 21315 if (!this.dimensions) { |
| 21316 return {}; |
| 21317 } |
| 21318 return { |
| 21319 dimensions: this.dimensions, |
| 21320 }; |
| 21260 }, | 21321 }, |
| 21261 | 21322 |
| 21262 _bots: function(){ | 21323 _bots: function(){ |
| 21263 if (!this._list || !this._list.items) { | 21324 if (!this._list || !this._list.items) { |
| 21264 return []; | 21325 return []; |
| 21265 } | 21326 } |
| 21266 this._list.items.forEach(function(o){ | 21327 // Do any preprocessing here |
| 21267 o.state = JSON.parse(o.state); | 21328 this._list.items.forEach(function(bot){ |
| 21329 // Parse the state, which is a JSON string. This contains a lot of |
| 21330 // interesting information like details about the devices attached. |
| 21331 bot.state = JSON.parse(bot.state); |
| 21332 // get the disks in an easier to deal with format, sorted by size. |
| 21333 var disks = bot.state["disks"]; |
| 21334 var keys = Object.keys(disks); |
| 21335 if (!keys || !keys.length) { |
| 21336 bot.disks = [{"id": "unknown", "mb": 0}]; |
| 21337 } else { |
| 21338 bot.disks = []; |
| 21339 for (var i = 0; i < keys.length; i++) { |
| 21340 bot.disks.push({"id":keys[i], "mb":disks[keys[i]].free_mb}); |
| 21341 } |
| 21342 // Sort these so the biggest disk comes first. |
| 21343 bot.disks.sort(function(a, b) { |
| 21344 return b.mb - a.mb; |
| 21345 }); |
| 21346 } |
| 21347 |
| 21268 }); | 21348 }); |
| 21269 return this._list.items; | 21349 return this._list.items; |
| 21270 }, | 21350 }, |
| 21271 | 21351 |
| 21272 _fleet: function() { | 21352 _fleet: function() { |
| 21273 if (!this._count) { | 21353 if (!this._count) { |
| 21274 return {}; | 21354 return {}; |
| 21275 } | 21355 } |
| 21276 return { | 21356 return { |
| 21277 alive: this._count.count || -1, | 21357 alive: this._count.count || -1, |
| 21278 busy: this._count.busy || -1, | 21358 busy: this._count.busy || -1, |
| 21279 idle: this._count.count && this._count.busy && | 21359 idle: this._count.count && this._count.busy && |
| 21280 this._count.count - this._count.busy, | 21360 this._count.count - this._count.busy, |
| 21281 dead: this._count.dead || -1, | 21361 dead: this._count.dead || -1, |
| 21282 quarantined: this._count.quarantined || -1, | 21362 quarantined: this._count.quarantined || -1, |
| 21283 } | 21363 } |
| 21284 }, | 21364 }, |
| 21285 | 21365 |
| 21286 _primaryMap: function(bots){ | 21366 _primaryArr: function(dimensions, properties) { |
| 21367 return dimensions.concat(properties); |
| 21368 }, |
| 21369 |
| 21370 _primaryMap: function(dimensions){ |
| 21287 // map will keep track of dimensions that we have seen at least once. | 21371 // map will keep track of dimensions that we have seen at least once. |
| 21288 // This will then basically get turned into an array to be used for | 21372 // This will then basically get turned into an array to be used for |
| 21289 // filtering. | 21373 // filtering. |
| 21290 var map = {}; | 21374 dimensions = dimensions.bots_dimensions; |
| 21291 DIMENSIONS.forEach(function(p){ | |
| 21292 map[p] = {}; | |
| 21293 }); | |
| 21294 map["devices"] = {}; | |
| 21295 map["gpu"] = {}; | |
| 21296 bots.forEach(function(b){ | |
| 21297 DIMENSIONS.forEach(function(d){ | |
| 21298 var dims = this._dimension(b, d) || []; | |
| 21299 dims.forEach(function(e){ | |
| 21300 map[d][e] = true; | |
| 21301 }); | |
| 21302 }.bind(this)); | |
| 21303 | 21375 |
| 21304 // Add Android devices and their aliases | 21376 var pMap = {}; |
| 21305 this._devices(b).forEach(function(d){ | 21377 dimensions.forEach(function(d){ |
| 21306 var dt = this._deviceType(d); | 21378 if (this.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) { |
| 21307 var alias = this._androidAlias(d); | 21379 // value is an array of all seen values for the dimension d.key |
| 21308 if (dt !== "unknown") { | 21380 pMap[d.key] = d.value; |
| 21309 dt = this._applyAlias(dt,alias); | 21381 } else if (d.key === "gpu") { |
| 21310 } | 21382 var gpus = []; |
| 21311 map["devices"][dt] = true; | 21383 d.value.forEach(function(g){ |
| 21312 }.bind(this)); | 21384 var alias = this._gpuAlias(g); |
| 21313 map["devices"]["none"] = true; | 21385 if (alias !== "unknown") { |
| 21314 | 21386 gpus.push(this._applyAlias(g, alias)); |
| 21315 // Add GPUs and their aliases | 21387 } else { |
| 21316 var gpus = this._dimension(b, "gpu") || []; | 21388 gpus.push(g); |
| 21317 gpus.forEach(function(g){ | 21389 } |
| 21318 var alias = this._gpuAlias(g); | 21390 }.bind(this)); |
| 21319 if (alias !== "UNKNOWN") { | 21391 pMap["gpu"] = gpus; |
| 21320 map["gpu"][this._applyAlias(g, alias)] = true; | 21392 } else if (d.key === "device_type") { |
| 21321 } else { | 21393 var devs = []; |
| 21322 map["gpu"][g] = true; | 21394 d.value.forEach(function(dt){ |
| 21323 } | 21395 var alias = this._androidAlias(dt); |
| 21324 | 21396 if (alias !== "unknown") { |
| 21325 }.bind(this)); | 21397 devs.push(this._applyAlias(dt, alias)); |
| 21398 } else { |
| 21399 devs.push(dt); |
| 21400 } |
| 21401 }.bind(this)); |
| 21402 pMap["device_type"] = devs; |
| 21403 } else { |
| 21404 console.log("Unknown alias type: ", d); |
| 21405 } |
| 21326 }.bind(this)); | 21406 }.bind(this)); |
| 21327 | 21407 |
| 21328 // Turn the Map<Object,Map<Boolean>> into a Map<Object,Array<String>> | 21408 // Add some options that might not show up. |
| 21329 // with all of the secondary elements sorted appropriately. | 21409 pMap["android_devices"].push("0"); |
| 21330 var pMap = {}; | 21410 pMap["device_os"].push("none"); |
| 21331 for (key in map){ | 21411 pMap["device_type"].push("none"); |
| 21332 pMap[key] = Object.keys(map[key]).sort(swarming.naturalCompare); | 21412 |
| 21333 } | 21413 pMap["id"] = []; |
| 21334 | 21414 |
| 21335 // Create custom filter options | 21415 // Create custom filter options |
| 21416 pMap["disk_space"] = []; |
| 21336 pMap["task"] = ["busy", "idle"]; | 21417 pMap["task"] = ["busy", "idle"]; |
| 21337 pMap["status"] = ["available", "dead", "quarantined"]; | 21418 pMap["status"] = ["available", "dead", "quarantined"]; |
| 21419 |
| 21420 // No need to sort any of this, bot-filters sorts secondary items |
| 21421 // automatically, especially when the user types a query. |
| 21338 return pMap; | 21422 return pMap; |
| 21339 }, | 21423 }, |
| 21340 | 21424 |
| 21341 }); | 21425 }); |
| 21342 })(); | 21426 })(); |
| 21343 </script> | 21427 </script> |
| 21344 </dom-module><dom-module id="bot-list-summary" assetpath="/res/imp/botlist/"> | 21428 </dom-module><dom-module id="bot-list-summary" assetpath="/res/imp/botlist/"> |
| 21345 <template> | 21429 <template> |
| 21346 <style include="swarming-app-style"> | 21430 <style include="swarming-app-style"> |
| 21347 :host { | 21431 :host { |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 21518 </style> | 21602 </style> |
| 21519 | 21603 |
| 21520 <swarming-app auth_headers="{{_auth_headers}}" signed_in="{{_signed_in}}" bu
sy="[[_busy]]" name="Swarming Bot List"> | 21604 <swarming-app auth_headers="{{_auth_headers}}" signed_in="{{_signed_in}}" bu
sy="[[_busy]]" name="Swarming Bot List"> |
| 21521 | 21605 |
| 21522 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> | 21606 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> |
| 21523 | 21607 |
| 21524 <div hidden$="[[_not(_signed_in)]]"> | 21608 <div hidden$="[[_not(_signed_in)]]"> |
| 21525 | 21609 |
| 21526 <div class="horizontal layout"> | 21610 <div class="horizontal layout"> |
| 21527 | 21611 |
| 21528 <bot-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_ar
r]]" columns="{{_columns}}" filter="{{_filter}}" verbose="{{_verbose}}"> | 21612 <bot-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_ar
r]]" columns="{{_columns}}" dimensions="{{_dimensions}}" filter="{{_filter}}" ve
rbose="{{_verbose}}"> |
| 21529 </bot-filters> | 21613 </bot-filters> |
| 21530 | 21614 |
| 21531 <bot-list-summary fleet="[[_fleet]]" filtered_bots="[[_filteredSortedB
ots]]"> | 21615 <bot-list-summary fleet="[[_fleet]]" filtered_bots="[[_filteredSortedB
ots]]"> |
| 21532 </bot-list-summary> | 21616 </bot-list-summary> |
| 21533 | 21617 |
| 21534 </div> | 21618 </div> |
| 21535 | 21619 |
| 21536 <bot-list-data auth_headers="[[_auth_headers]]" bots="{{_bots}}" busy="{
{_busy}}" fleet="{{_fleet}}" primary_map="{{_primary_map}}" primary_arr="{{_prim
ary_arr}}"> | 21620 <bot-list-data auth_headers="[[_auth_headers]]" dimensions="[[_dimension
s]]" bots="{{_bots}}" busy="{{_busy}}" fleet="{{_fleet}}" primary_map="{{_primar
y_map}}" primary_arr="{{_primary_arr}}"> |
| 21537 </bot-list-data> | 21621 </bot-list-data> |
| 21538 | 21622 |
| 21539 <table class="bot-list"> | 21623 <table class="bot-list"> |
| 21540 <thead on-sort_change="_sortChange"> | 21624 <thead on-sort_change="_sortChange"> |
| 21541 | 21625 |
| 21542 <tr> | 21626 <tr> |
| 21543 <th> | 21627 <th> |
| 21544 <span>Bot Id</span> | 21628 <span>Bot Id</span> |
| 21545 <sort-toggle name="id" current="[[_sort]]"> | 21629 <sort-toggle name="id" current="[[_sort]]"> |
| 21546 </sort-toggle> | 21630 </sort-toggle> |
| (...skipping 28 matching lines...) Expand all Loading... |
| 21575 </td> | 21659 </td> |
| 21576 | 21660 |
| 21577 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> | 21661 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> |
| 21578 <td hidden$="[[_hide(c)]]"> | 21662 <td hidden$="[[_hide(c)]]"> |
| 21579 [[_column(c, bot, _verbose)]] | 21663 [[_column(c, bot, _verbose)]] |
| 21580 </td> | 21664 </td> |
| 21581 </template> | 21665 </template> |
| 21582 | 21666 |
| 21583 </tr> | 21667 </tr> |
| 21584 <template is="dom-repeat" items="[[_devices(bot)]]" as="device"> | 21668 <template is="dom-repeat" items="[[_devices(bot)]]" as="device"> |
| 21585 <tr hidden$="[[_hide('devices', _columns.*)]]" class$="[[_device
Class(device)]]"> | 21669 <tr hidden$="[[_hide('android_devices', _columns.*)]]" class$="[
[_deviceClass(device)]]"> |
| 21586 <td></td> | 21670 <td></td> |
| 21587 <td hidden$="[[_hide('task', _columns.*)]]"></td> | 21671 <td hidden$="[[_hide('task', _columns.*)]]"></td> |
| 21588 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> | 21672 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> |
| 21589 <td hidden$="[[_hide(c)]]"> | 21673 <td hidden$="[[_hide(c)]]"> |
| 21590 [[_deviceColumn(c, device, _verbose)]] | 21674 [[_deviceColumn(c, device, _verbose)]] |
| 21591 </td> | 21675 </td> |
| 21592 </template> | 21676 </template> |
| 21593 </tr> | 21677 </tr> |
| 21594 </template> | 21678 </template> |
| 21595 </template> | 21679 </template> |
| 21596 </tbody> | 21680 </tbody> |
| 21597 </table> | 21681 </table> |
| 21598 </div> | 21682 </div> |
| 21599 | 21683 |
| 21600 </swarming-app> | 21684 </swarming-app> |
| 21601 | 21685 |
| 21602 </template> | 21686 </template> |
| 21603 <script> | 21687 <script> |
| 21604 (function(){ | 21688 (function(){ |
| 21605 var special_columns = ["id", "task"]; | 21689 var special_columns = ["id", "task"]; |
| 21606 | 21690 |
| 21607 var headerMap = { | 21691 var headerMap = { |
| 21608 // "id" and "task" are special, so they don't go here and have their | 21692 // "id" and "task" are special, so they don't go here and have their |
| 21609 // headers hard-coded below. | 21693 // headers hard-coded below. |
| 21694 "android_devices": "Android Devices", |
| 21610 "cores": "Cores", | 21695 "cores": "Cores", |
| 21611 "cpu": "CPU", | 21696 "cpu": "CPU", |
| 21612 "devices": "Devices", | 21697 "device_os": "Device OS", |
| 21698 "device_type": "Device Type", |
| 21699 "disk_space": "Free Space (MB)", |
| 21613 "gpu": "GPU", | 21700 "gpu": "GPU", |
| 21614 "os": "OS", | 21701 "os": "OS", |
| 21615 "pool": "Pool", | 21702 "pool": "Pool", |
| 21616 "status": "Status", | 21703 "status": "Status", |
| 21617 }; | 21704 }; |
| 21618 | 21705 |
| 21619 // This maps column name to a function that will return the content for a | 21706 // This maps column name to a function that will return the content for a |
| 21620 // given bot. These functions are bound to this element, and have access | 21707 // given bot. These functions are bound to this element, and have access |
| 21621 // to all functions defined here and in bot-list-shared. | 21708 // to all functions defined here and in bot-list-shared. |
| 21622 var columnMap = { | 21709 var columnMap = { |
| 21710 android_devices: function(bot) { |
| 21711 var devs = this._attribute(bot, "android_devices", "0"); |
| 21712 if (this._verbose) { |
| 21713 return devs.join(" | ") + " devices available"; |
| 21714 } |
| 21715 // max() works on strings as long as they can be coerced to Number. |
| 21716 return Math.max(...devs) + " devices available"; |
| 21717 }, |
| 21623 cores: function(bot){ | 21718 cores: function(bot){ |
| 21624 var cores = this._cores(bot); | 21719 var cores = this._attribute(bot, "cores"); |
| 21625 if (this._verbose){ | 21720 if (this._verbose){ |
| 21626 return cores.join(" | "); | 21721 return cores.join(" | "); |
| 21627 } | 21722 } |
| 21628 return cores[0]; | 21723 return cores[0]; |
| 21629 }, | 21724 }, |
| 21630 cpu: function(bot){ | 21725 cpu: function(bot){ |
| 21631 var cpus = this._dimension(bot, 'cpu') || ['Unknown']; | 21726 var cpus = this._attribute(bot, "cpu"); |
| 21632 if (this._verbose){ | 21727 if (this._verbose){ |
| 21633 return cpus.join(" | "); | 21728 return cpus.join(" | "); |
| 21634 } | 21729 } |
| 21635 return cpus[0]; | 21730 return cpus[0]; |
| 21636 }, | 21731 }, |
| 21637 devices: function(bot){ | 21732 device_os: function(bot){ |
| 21638 return this._devices(bot).length + " devices attached"; | 21733 var os = this._attribute(bot, "device_os", "none"); |
| 21734 if (this._verbose) { |
| 21735 return os.join(" | "); |
| 21736 } |
| 21737 return os[0]; |
| 21738 }, |
| 21739 device_type: function(bot){ |
| 21740 var dt = this._attribute(bot, "device_type", "none"); |
| 21741 if (this._verbose) { |
| 21742 return dt.join(" | "); |
| 21743 } |
| 21744 return dt[0]; |
| 21745 }, |
| 21746 disk_space: function(bot) { |
| 21747 var aliased = []; |
| 21748 bot.disks.forEach(function(disk){ |
| 21749 var alias = swarming.humanBytes(disk.mb, swarming.MB); |
| 21750 aliased.push(this._applyAlias(disk.mb, disk.id + " "+ alias)); |
| 21751 }.bind(this)); |
| 21752 if (this._verbose) { |
| 21753 return aliased.join(" | "); |
| 21754 } |
| 21755 return aliased[0]; |
| 21639 }, | 21756 }, |
| 21640 gpu: function(bot){ | 21757 gpu: function(bot){ |
| 21641 var gpus = this._dimension(bot, 'gpu') | 21758 var gpus = this._attribute(bot, "gpu", "none") |
| 21642 if (!gpus) { | |
| 21643 return "none"; | |
| 21644 } | |
| 21645 var verbose = [] | 21759 var verbose = [] |
| 21646 var named = []; | 21760 var named = []; |
| 21647 // non-verbose mode has only the top level GPU info "e.g. NVidia" | 21761 // non-verbose mode has only the top level GPU info "e.g. NVidia" |
| 21648 // which is found by looking for gpu ids w/o a colon. | 21762 // which is found by looking for gpu ids w/o a colon. |
| 21649 gpus.forEach(function(g){ | 21763 gpus.forEach(function(g){ |
| 21650 var alias = this._gpuAlias(g); | 21764 var alias = this._gpuAlias(g); |
| 21651 if (alias === "UNKNOWN") { | 21765 if (alias === "unknown") { |
| 21652 verbose.push(g); | 21766 verbose.push(g); |
| 21653 if (g.indexOf(":") === -1) { | 21767 if (g.indexOf(":") === -1) { |
| 21654 named.push(g); | 21768 named.push(g); |
| 21655 } | 21769 } |
| 21656 return; | 21770 return; |
| 21657 } | 21771 } |
| 21658 verbose.push(this._applyAlias(g, alias)); | 21772 verbose.push(this._applyAlias(g, alias)); |
| 21659 if (g.indexOf(":") === -1) { | 21773 if (g.indexOf(":") === -1) { |
| 21660 named.push(this._applyAlias(g, alias)); | 21774 named.push(this._applyAlias(g, alias)); |
| 21661 } | 21775 } |
| 21662 }.bind(this)) | 21776 }.bind(this)) |
| 21663 if (this._verbose) { | 21777 if (this._verbose) { |
| 21664 return verbose.join(" | "); | 21778 return verbose.join(" | "); |
| 21665 } | 21779 } |
| 21666 return named.join(" | "); | 21780 return named.join(" | "); |
| 21667 }, | 21781 }, |
| 21668 id: function(bot) { | 21782 id: function(bot) { |
| 21669 return bot.bot_id; | 21783 return bot.bot_id; |
| 21670 }, | 21784 }, |
| 21671 os: function(bot) { | 21785 os: function(bot) { |
| 21672 var os = this._dimension(bot, 'os') || ['Unknown']; | 21786 var os = this._attribute(bot, "os"); |
| 21673 if (this._verbose){ | 21787 if (this._verbose){ |
| 21674 return os.join(" | "); | 21788 return os.join(" | "); |
| 21675 } | 21789 } |
| 21676 return os[0]; | 21790 return os[0]; |
| 21677 }, | 21791 }, |
| 21678 pool: function(bot) { | 21792 pool: function(bot) { |
| 21679 var pool = this._dimension(bot, 'pool') || ['Unknown']; | 21793 var pool = this._attribute(bot, "pool"); |
| 21680 return pool.join(" | "); | 21794 return pool.join(" | "); |
| 21681 }, | 21795 }, |
| 21682 status: function(bot) { | 21796 status: function(bot) { |
| 21683 // If a bot is both dead and quarantined, show the deadness over the | 21797 // If a bot is both dead and quarantined, show the deadness over the |
| 21684 // quarentinedness. | 21798 // quarentinedness. |
| 21685 if (bot.is_dead) { | 21799 if (bot.is_dead) { |
| 21686 return "Dead: " + bot.is_dead; | 21800 return "Dead. Last seen " + swarming.diffDate(bot.last_seen_ts) + |
| 21801 " ago"; |
| 21687 } | 21802 } |
| 21688 if (bot.quarantined) { | 21803 if (bot.quarantined) { |
| 21689 return "Quarantined: " + bot.quarantined; | 21804 return "Quarantined: " + this._attribute(bot, "quarantined"); |
| 21690 } | 21805 } |
| 21691 return "Alive"; | 21806 return "Alive"; |
| 21692 }, | 21807 }, |
| 21693 task: function(bot){ | 21808 task: function(bot){ |
| 21694 return this._taskId(bot); | 21809 return this._taskId(bot); |
| 21695 }, | 21810 }, |
| 21696 }; | 21811 }; |
| 21697 | 21812 |
| 21813 var deviceColumnMap = { |
| 21814 android_devices: function(device) { |
| 21815 var str = this._androidAliasDevice(device); |
| 21816 if (device.okay) { |
| 21817 str = this._applyAlias(this._deviceType(device), str); |
| 21818 } |
| 21819 str += " S/N:"; |
| 21820 str += device.serial; |
| 21821 return str; |
| 21822 }, |
| 21823 device_os: function(device) { |
| 21824 if (device.build) { |
| 21825 return device.build["build.id"]; |
| 21826 } |
| 21827 return "unknown"; |
| 21828 }, |
| 21829 status: function(device) { |
| 21830 return device.state; |
| 21831 } |
| 21832 } |
| 21833 |
| 21834 // specialSort defines any custom sorting rules. By default, a |
| 21835 // naturalCompare of the column content is done. |
| 21836 var specialSort = { |
| 21837 device_type: function(dir, botA, botB) { |
| 21838 // We sort on the number of attached devices. Note that this |
| 21839 // may not be the same as android_devices, because _devices().length |
| 21840 // counts all devices plugged into the bot, whereas android_devices |
| 21841 // counts just devices ready for work. |
| 21842 var botACol = this._devices(botA).length; |
| 21843 var botBCol = this._devices(botB).length; |
| 21844 return dir * swarming.naturalCompare(botACol, botBCol); |
| 21845 }, |
| 21846 disk_space: function(dir, botA, botB) { |
| 21847 // We sort based on the raw number of MB of the first disk. |
| 21848 var botACol = botA.disks[0].mb; |
| 21849 var botBCol = botB.disks[0].mb;; |
| 21850 return dir * swarming.naturalCompare(botACol, botBCol); |
| 21851 }, |
| 21852 }; |
| 21853 |
| 21698 Polymer({ | 21854 Polymer({ |
| 21699 is: 'bot-list', | 21855 is: 'bot-list', |
| 21700 behaviors: [SwarmingBehaviors.BotListBehavior], | 21856 behaviors: [SwarmingBehaviors.BotListBehavior], |
| 21701 | 21857 |
| 21702 properties: { | 21858 properties: { |
| 21703 | 21859 |
| 21704 _bots: { | 21860 _bots: { |
| 21705 type: Array, | 21861 type: Array, |
| 21706 }, | 21862 }, |
| 21707 | 21863 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 21755 _botLink: function(id) { | 21911 _botLink: function(id) { |
| 21756 // TODO(kjlubick) Make this point to /newui/ when appropriate. | 21912 // TODO(kjlubick) Make this point to /newui/ when appropriate. |
| 21757 return "/restricted/bot/"+id; | 21913 return "/restricted/bot/"+id; |
| 21758 }, | 21914 }, |
| 21759 | 21915 |
| 21760 | 21916 |
| 21761 _column: function(col, bot) { | 21917 _column: function(col, bot) { |
| 21762 return columnMap[col].bind(this)(bot); | 21918 return columnMap[col].bind(this)(bot); |
| 21763 }, | 21919 }, |
| 21764 | 21920 |
| 21921 _androidAliasDevice: function(device) { |
| 21922 if (device.notReady) { |
| 21923 return UNAUTHENTICATED.toUpperCase(); |
| 21924 } |
| 21925 return this._androidAlias(this._deviceType(device)); |
| 21926 }, |
| 21927 |
| 21765 _deviceColumn: function(col, device) { | 21928 _deviceColumn: function(col, device) { |
| 21766 if (col === "devices") { | 21929 var f = deviceColumnMap[col]; |
| 21767 var str = this._androidAlias(device); | 21930 if (!f || !device) { |
| 21768 if (device.okay) { | 21931 return ""; |
| 21769 str = this._applyAlias(this._deviceType(device), str); | |
| 21770 } | |
| 21771 str += " S/N:"; | |
| 21772 str += device.serial; | |
| 21773 return str; | |
| 21774 } | 21932 } |
| 21775 if (col === "status") { | 21933 return f.bind(this)(device); |
| 21776 return device.state; | |
| 21777 } | |
| 21778 return ""; | |
| 21779 }, | 21934 }, |
| 21780 | 21935 |
| 21781 _deviceClass: function(device) { | 21936 _deviceClass: function(device) { |
| 21782 if (!device.okay) { | 21937 if (!device.okay) { |
| 21783 return "bad-device"; | 21938 return "bad-device"; |
| 21784 } | 21939 } |
| 21785 return ""; | 21940 return ""; |
| 21786 }, | 21941 }, |
| 21787 | 21942 |
| 21788 _filterAndSort: function(a,b,c) { | 21943 _filterAndSort: function(a,b,c) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 21811 }, | 21966 }, |
| 21812 | 21967 |
| 21813 _sortBotTable: function(botA, botB) { | 21968 _sortBotTable: function(botA, botB) { |
| 21814 if (!this._sort) { | 21969 if (!this._sort) { |
| 21815 return 0; | 21970 return 0; |
| 21816 } | 21971 } |
| 21817 var dir = 1; | 21972 var dir = 1; |
| 21818 if (this._sort.direction === "desc") { | 21973 if (this._sort.direction === "desc") { |
| 21819 dir = -1; | 21974 dir = -1; |
| 21820 } | 21975 } |
| 21976 var sort = specialSort[this._sort.name]; |
| 21977 if (sort) { |
| 21978 return sort.bind(this)(dir, botA, botB); |
| 21979 } |
| 21980 // Default to a natural compare of the columns. |
| 21821 var botACol = this._column(this._sort.name, botA); | 21981 var botACol = this._column(this._sort.name, botA); |
| 21822 var botBCol = this._column(this._sort.name, botB); | 21982 var botBCol = this._column(this._sort.name, botB); |
| 21823 | 21983 |
| 21824 return dir * swarming.naturalCompare(botACol, botBCol); | 21984 return dir * swarming.naturalCompare(botACol, botBCol); |
| 21825 }, | 21985 }, |
| 21826 | 21986 |
| 21827 _sortChange: function(e) { | 21987 _sortChange: function(e) { |
| 21828 // The event we get from sort-toggle tells us the name of what needs | 21988 // The event we get from sort-toggle tells us the name of what needs |
| 21829 // to be sorting and how to sort it. | 21989 // to be sorting and how to sort it. |
| 21830 if (!(e && e.detail && e.detail.name)) { | 21990 if (!(e && e.detail && e.detail.name)) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 21847 if (data && data.task_id) { | 22007 if (data && data.task_id) { |
| 21848 return "/user/task/" + data.task_id; | 22008 return "/user/task/" + data.task_id; |
| 21849 } | 22009 } |
| 21850 return undefined; | 22010 return undefined; |
| 21851 } | 22011 } |
| 21852 | 22012 |
| 21853 }); | 22013 }); |
| 21854 })(); | 22014 })(); |
| 21855 </script> | 22015 </script> |
| 21856 </dom-module></div></body></html> | 22016 </dom-module></div></body></html> |
| OLD | NEW |