| 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 14681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14692 type: String, | 14692 type: String, |
| 14693 } | 14693 } |
| 14694 }, | 14694 }, |
| 14695 | 14695 |
| 14696 signIn: function(){ | 14696 signIn: function(){ |
| 14697 this.$.request.generateRequest(); | 14697 this.$.request.generateRequest(); |
| 14698 }, | 14698 }, |
| 14699 | 14699 |
| 14700 }); | 14700 }); |
| 14701 </script> | 14701 </script> |
| 14702 </dom-module><dom-module id="dynamic-table-style" assetpath="/res/imp/common/"> | 14702 </dom-module><script> |
| 14703 (function(){ |
| 14704 var ANDROID_ALIASES = { |
| 14705 "bullhead": "Nexus 5X", |
| 14706 "flo": "Nexus 7 (2013)", |
| 14707 "flounder": "Nexus 9", |
| 14708 "foster": "NVIDIA Shield", |
| 14709 "fugu": "Nexus Player", |
| 14710 "grouper": "Nexus 7 (2012)", |
| 14711 "hammerhead": "Nexus 5", |
| 14712 "m0": "Galaxy S3", |
| 14713 "mako": "Nexus 4", |
| 14714 "manta": "Nexus 10", |
| 14715 "shamu": "Nexus 6", |
| 14716 "sprout": "Android One", |
| 14717 }; |
| 14718 |
| 14719 var UNKNOWN = "unknown"; |
| 14720 |
| 14721 var GPU_ALIASES = { |
| 14722 "1002": "AMD", |
| 14723 "1002:6779": "AMD Radeon HD 6450/7450/8450", |
| 14724 "1002:6821": "AMD Radeon HD 8870M", |
| 14725 "1002:683d": "AMD Radeon HD 7770/8760", |
| 14726 "1002:9830": "AMD Radeon HD 8400", |
| 14727 "102b": "Matrox", |
| 14728 "102b:0522": "Matrox MGA G200e", |
| 14729 "102b:0532": "Matrox MGA G200eW", |
| 14730 "102b:0534": "Matrox G200eR2", |
| 14731 "10de": "NVIDIA", |
| 14732 "10de:08a4": "NVIDIA GeForce 320M", |
| 14733 "10de:08aa": "NVIDIA GeForce 320M", |
| 14734 "10de:0fe9": "NVIDIA GeForce GT 750M Mac Edition", |
| 14735 "10de:104a": "NVIDIA GeForce GT 610", |
| 14736 "10de:11c0": "NVIDIA GeForce GTX 660", |
| 14737 "10de:1244": "NVIDIA GeForce GTX 550 Ti", |
| 14738 "10de:1401": "NVIDIA GeForce GTX 960", |
| 14739 "8086": "Intel", |
| 14740 "8086:0412": "Intel Haswell Integrated", |
| 14741 "8086:041a": "Intel Xeon Integrated", |
| 14742 "8086:0a2e": "Intel Haswell Integrated", |
| 14743 "8086:0d26": "Intel Crystal Well Integrated", |
| 14744 "8086:22b1": "Intel Braswell Integrated", |
| 14745 } |
| 14746 |
| 14747 // For consistency, all aliases are displayed like: |
| 14748 // Nexus 5X (bullhead) |
| 14749 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. |
| 14750 var ALIAS_REGEXP = /.+ \((.*)\)/; |
| 14751 |
| 14752 // This behavior wraps up all the shared bot-list functionality by |
| 14753 // extending SwarmingBehaviors.SwarmingBehavior |
| 14754 SwarmingBehaviors.Aliases = { |
| 14755 |
| 14756 properties: { |
| 14757 DIMENSIONS_WITH_ALIASES: { |
| 14758 type: Array, |
| 14759 value: function(){ |
| 14760 return ["device_type", "gpu"]; |
| 14761 }, |
| 14762 }, |
| 14763 }, |
| 14764 |
| 14765 _androidAlias: function(dt) { |
| 14766 return ANDROID_ALIASES[dt] || UNKNOWN; |
| 14767 }, |
| 14768 |
| 14769 // _applyAlias is the consistent way to modify a string to show its alias. |
| 14770 _applyAlias: function(orig, alias) { |
| 14771 return alias +" ("+orig+")"; |
| 14772 }, |
| 14773 |
| 14774 _gpuAlias: function(gpu) { |
| 14775 return GPU_ALIASES[gpu] || UNKNOWN; |
| 14776 }, |
| 14777 |
| 14778 // _unalias will return the base dimension/state with its alias removed |
| 14779 // if it had one. This is handy for sorting and filtering. |
| 14780 _unalias: function(str) { |
| 14781 var match = ALIAS_REGEXP.exec(str); |
| 14782 if (match) { |
| 14783 return match[1]; |
| 14784 } |
| 14785 return str; |
| 14786 }, |
| 14787 }; |
| 14788 })() |
| 14789 </script> |
| 14790 <dom-module id="dynamic-table-style" assetpath="/res/imp/common/"> |
| 14703 <template> | 14791 <template> |
| 14704 <style> | 14792 <style> |
| 14705 table { | 14793 table { |
| 14706 border-collapse: collapse; | 14794 border-collapse: collapse; |
| 14707 margin-left: 5px; | 14795 margin-left: 5px; |
| 14708 } | 14796 } |
| 14709 td, th { | 14797 td, th { |
| 14710 border: 1px solid #DDD; | 14798 border: 1px solid #DDD; |
| 14711 padding: 5px; | 14799 padding: 5px; |
| 14712 } | 14800 } |
| 14713 th { | 14801 th { |
| 14714 position: relative; | 14802 position: relative; |
| 14715 } | 14803 } |
| 14716 sort-toggle { | 14804 sort-toggle { |
| 14717 position: absolute; | 14805 position: absolute; |
| 14718 right: 0; | 14806 right: 0; |
| 14719 top: 0.4em; | 14807 top: 0.4em; |
| 14720 } | 14808 } |
| 14721 </style> | 14809 </style> |
| 14722 | 14810 |
| 14723 </template> | 14811 </template> |
| 14724 </dom-module> | 14812 </dom-module> |
| 14725 | 14813 |
| 14726 <script> | 14814 <script> |
| 14727 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; | |
| 14728 (function(){ | 14815 (function(){ |
| 14729 // This behavior wraps up all the shared swarming functionality. | 14816 // This behavior wraps up all the shared swarming functionality. |
| 14730 SwarmingBehaviors.DynamicTableBehavior = { | 14817 SwarmingBehaviors.DynamicTableBehavior = [SwarmingBehaviors.Aliases, { |
| 14731 | 14818 |
| 14732 properties: { | 14819 properties: { |
| 14733 | 14820 |
| 14734 _columns: { | 14821 _columns: { |
| 14735 type: Array, | 14822 type: Array, |
| 14736 }, | 14823 }, |
| 14737 | 14824 |
| 14738 _filter: { | 14825 _filter: { |
| 14739 type: Function, | 14826 type: Function, |
| 14740 }, | 14827 }, |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14848 }, | 14935 }, |
| 14849 // _stripSpecial removes the special columns and sorts the remaining | 14936 // _stripSpecial removes the special columns and sorts the remaining |
| 14850 // columns so they always appear in the same order, regardless of | 14937 // columns so they always appear in the same order, regardless of |
| 14851 // the order they are added. | 14938 // the order they are added. |
| 14852 _stripSpecial: function(){ | 14939 _stripSpecial: function(){ |
| 14853 return this._columns.filter(function(c) { | 14940 return this._columns.filter(function(c) { |
| 14854 return this._specialColumns.indexOf(c) === -1; | 14941 return this._specialColumns.indexOf(c) === -1; |
| 14855 }.bind(this)).sort(); | 14942 }.bind(this)).sort(); |
| 14856 }, | 14943 }, |
| 14857 | 14944 |
| 14858 }; | 14945 // Common columns shared between tasklist and botlist |
| 14946 _commonColumns: function() { |
| 14947 // return a fresh object so all elements have their own copy |
| 14948 return { |
| 14949 android_devices: function(bot) { |
| 14950 var devs = this._attribute(bot, "android_devices", "0"); |
| 14951 if (this._verbose) { |
| 14952 return devs.join(" | ") + " devices available"; |
| 14953 } |
| 14954 // max() works on strings as long as they can be coerced to Number. |
| 14955 return Math.max(...devs) + " devices available"; |
| 14956 }, |
| 14957 device_type: function(bot) { |
| 14958 var dt = this._attribute(bot, "device_type", "none"); |
| 14959 dt = dt[0]; |
| 14960 var alias = this._androidAlias(dt); |
| 14961 if (alias === "unknown") { |
| 14962 return dt; |
| 14963 } |
| 14964 return this._applyAlias(dt, alias); |
| 14965 }, |
| 14966 gpu: function(bot){ |
| 14967 var gpus = this._attribute(bot, "gpu", "none"); |
| 14968 var verbose = [] |
| 14969 var named = []; |
| 14970 // non-verbose mode has only the top level GPU info "e.g. NVidia" |
| 14971 // which is found by looking for gpu ids w/o a colon. |
| 14972 gpus.forEach(function(g){ |
| 14973 var alias = this._gpuAlias(g); |
| 14974 if (alias === "unknown") { |
| 14975 verbose.push(g); |
| 14976 if (g.indexOf(":") === -1) { |
| 14977 named.push(g); |
| 14978 } |
| 14979 return; |
| 14980 } |
| 14981 verbose.push(this._applyAlias(g, alias)); |
| 14982 if (g.indexOf(":") === -1) { |
| 14983 named.push(this._applyAlias(g, alias)); |
| 14984 } |
| 14985 }.bind(this)) |
| 14986 if (this._verbose || !named.length) { |
| 14987 return verbose.join(" | "); |
| 14988 } |
| 14989 return named.join(" | "); |
| 14990 }, |
| 14991 pool: function(bot) { |
| 14992 var pool = this._attribute(bot, "pool"); |
| 14993 return pool.join(" | "); |
| 14994 }, |
| 14995 }; |
| 14996 }, |
| 14997 |
| 14998 |
| 14999 }]; |
| 14859 })(); | 15000 })(); |
| 14860 </script> | 15001 </script> |
| 14861 | 15002 |
| 14862 <script> | 15003 <script> |
| 14863 | 15004 |
| 14864 (function() { | 15005 (function() { |
| 14865 | 15006 |
| 14866 // monostate data | 15007 // monostate data |
| 14867 var metaDatas = {}; | 15008 var metaDatas = {}; |
| 14868 var metaArrays = {}; | 15009 var metaArrays = {}; |
| (...skipping 7990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 22859 <script> | 23000 <script> |
| 22860 Polymer({ | 23001 Polymer({ |
| 22861 is: 'paper-input', | 23002 is: 'paper-input', |
| 22862 | 23003 |
| 22863 behaviors: [ | 23004 behaviors: [ |
| 22864 Polymer.IronFormElementBehavior, | 23005 Polymer.IronFormElementBehavior, |
| 22865 Polymer.PaperInputBehavior | 23006 Polymer.PaperInputBehavior |
| 22866 ] | 23007 ] |
| 22867 }); | 23008 }); |
| 22868 </script> | 23009 </script> |
| 22869 <script> | 23010 <dom-module id="query-column-filter-style" assetpath="/res/imp/common/"> |
| 22870 (function(){ | |
| 22871 var ANDROID_ALIASES = { | |
| 22872 "bullhead": "Nexus 5X", | |
| 22873 "flo": "Nexus 7 (2013)", | |
| 22874 "flounder": "Nexus 9", | |
| 22875 "foster": "NVIDIA Shield", | |
| 22876 "fugu": "Nexus Player", | |
| 22877 "grouper": "Nexus 7 (2012)", | |
| 22878 "hammerhead": "Nexus 5", | |
| 22879 "m0": "Galaxy S3", | |
| 22880 "mako": "Nexus 4", | |
| 22881 "manta": "Nexus 10", | |
| 22882 "shamu": "Nexus 6", | |
| 22883 "sprout": "Android One", | |
| 22884 }; | |
| 22885 // Taken from http://developer.android.com/reference/android/os/BatteryManag
er.html | |
| 22886 var BATTERY_HEALTH_UNKNOWN = 1; | |
| 22887 var BATTERY_HEALTH_GOOD = 2; | |
| 22888 var BATTERY_STATUS_CHARGING = 2; | |
| 22889 | |
| 22890 var UNAUTHENTICATED = "unauthenticated"; | |
| 22891 var AVAILABLE = "available"; | |
| 22892 var UNKNOWN = "unknown"; | |
| 22893 | |
| 22894 var GPU_ALIASES = { | |
| 22895 "1002": "AMD", | |
| 22896 "1002:6779": "AMD Radeon HD 6450/7450/8450", | |
| 22897 "1002:6821": "AMD Radeon HD 8870M", | |
| 22898 "1002:683d": "AMD Radeon HD 7770/8760", | |
| 22899 "1002:9830": "AMD Radeon HD 8400", | |
| 22900 "102b": "Matrox", | |
| 22901 "102b:0522": "Matrox MGA G200e", | |
| 22902 "102b:0532": "Matrox MGA G200eW", | |
| 22903 "102b:0534": "Matrox G200eR2", | |
| 22904 "10de": "NVIDIA", | |
| 22905 "10de:08a4": "NVIDIA GeForce 320M", | |
| 22906 "10de:08aa": "NVIDIA GeForce 320M", | |
| 22907 "10de:0fe9": "NVIDIA GeForce GT 750M Mac Edition", | |
| 22908 "10de:104a": "NVIDIA GeForce GT 610", | |
| 22909 "10de:11c0": "NVIDIA GeForce GTX 660", | |
| 22910 "10de:1244": "NVIDIA GeForce GTX 550 Ti", | |
| 22911 "10de:1401": "NVIDIA GeForce GTX 960", | |
| 22912 "8086": "Intel", | |
| 22913 "8086:0412": "Intel Haswell Integrated", | |
| 22914 "8086:041a": "Intel Xeon Integrated", | |
| 22915 "8086:0a2e": "Intel Haswell Integrated", | |
| 22916 "8086:0d26": "Intel Crystal Well Integrated", | |
| 22917 "8086:22b1": "Intel Braswell Integrated", | |
| 22918 } | |
| 22919 | |
| 22920 // For consistency, all aliases are displayed like: | |
| 22921 // Nexus 5X (bullhead) | |
| 22922 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. | |
| 22923 var ALIAS_REGEXP = /.+ \((.*)\)/; | |
| 22924 | |
| 22925 // This behavior wraps up all the shared bot-list functionality by | |
| 22926 // extending SwarmingBehaviors.SwarmingBehavior | |
| 22927 SwarmingBehaviors.BotListBehavior = [SwarmingBehaviors.SwarmingBehavior, { | |
| 22928 | |
| 22929 properties: { | |
| 22930 DIMENSIONS_WITH_ALIASES: { | |
| 22931 type: Array, | |
| 22932 value: function(){ | |
| 22933 return ["device_type", "gpu"]; | |
| 22934 }, | |
| 22935 }, | |
| 22936 BOT_PROPERTIES: { | |
| 22937 type: Array, | |
| 22938 value: function() { | |
| 22939 // TODO(kjlubick): Add more of these things from state, as they | |
| 22940 // needed/useful/requested. | |
| 22941 return ["disk_space", "task", "status"]; | |
| 22942 } | |
| 22943 }, | |
| 22944 }, | |
| 22945 | |
| 22946 _androidAlias: function(dt) { | |
| 22947 return ANDROID_ALIASES[dt] || UNKNOWN; | |
| 22948 }, | |
| 22949 | |
| 22950 // _applyAlias is the consistent way to modify a string to show its alias. | |
| 22951 _applyAlias: function(orig, alias) { | |
| 22952 return alias +" ("+orig+")"; | |
| 22953 }, | |
| 22954 | |
| 22955 // _attribute looks first in dimension and then in state for the | |
| 22956 // specified attribute. This will always return an array. If there is | |
| 22957 // no matching attribute, ["unknown"] will be returned. | |
| 22958 _attribute: function(bot, attr, none) { | |
| 22959 none = none || UNKNOWN; | |
| 22960 return this._dimension(bot, attr) || this._state(bot, attr) || [none]; | |
| 22961 }, | |
| 22962 | |
| 22963 _devices: function(bot) { | |
| 22964 var devices = []; | |
| 22965 var d = (bot && bot.state && bot.state.devices) || {}; | |
| 22966 // state.devices is like {Serial:Object}, so we need to keep the serial | |
| 22967 for (key in d) { | |
| 22968 var o = d[key]; | |
| 22969 o.serial = key; | |
| 22970 o.okay = (o.state === AVAILABLE); | |
| 22971 // It is easier to assume all devices on a bot are of the same type | |
| 22972 // than to pick through the (incomplete) device state and find it. | |
| 22973 o.device_type = this._attribute(bot, "device_type")[0]; | |
| 22974 devices.push(o); | |
| 22975 } | |
| 22976 return devices; | |
| 22977 }, | |
| 22978 | |
| 22979 // _deviceType returns the codename of a given Android device. | |
| 22980 _deviceType: function(device) { | |
| 22981 return device.device_type.toLowerCase(); | |
| 22982 }, | |
| 22983 | |
| 22984 // _dimension returns the given dimension of a bot. If it is defined, it | |
| 22985 // is an array of strings. | |
| 22986 _dimension: function(bot, dim) { | |
| 22987 if (!bot || !bot.dimensions || !dim) { | |
| 22988 return undefined; | |
| 22989 } | |
| 22990 for (var i = 0; i < bot.dimensions.length; i++) { | |
| 22991 if (bot.dimensions[i].key === dim) { | |
| 22992 return bot.dimensions[i].value; | |
| 22993 } | |
| 22994 } | |
| 22995 return undefined; | |
| 22996 }, | |
| 22997 | |
| 22998 _gpuAlias: function(gpu) { | |
| 22999 return GPU_ALIASES[gpu] || UNKNOWN; | |
| 23000 }, | |
| 23001 | |
| 23002 // _state returns the requested attribute from a bot's state. | |
| 23003 // For consistency with _dimension, if the attribute is not an array, | |
| 23004 // it is put as the only element in an array. | |
| 23005 _state: function(bot, attr) { | |
| 23006 if (!bot || !bot.state || !bot.state[attr]) { | |
| 23007 return undefined | |
| 23008 } | |
| 23009 var state = bot.state[attr]; | |
| 23010 if (Array.isArray(state)) { | |
| 23011 return state; | |
| 23012 } | |
| 23013 return [state]; | |
| 23014 }, | |
| 23015 | |
| 23016 _taskId: function(bot) { | |
| 23017 if (bot && bot.task_id) { | |
| 23018 return bot.task_id; | |
| 23019 } | |
| 23020 return "idle"; | |
| 23021 }, | |
| 23022 | |
| 23023 // _unalias will return the base dimension/state with its alias removed | |
| 23024 // if it had one. This is handy for sorting and filtering. | |
| 23025 _unalias: function(str) { | |
| 23026 var match = ALIAS_REGEXP.exec(str); | |
| 23027 if (match) { | |
| 23028 return match[1]; | |
| 23029 } | |
| 23030 return str; | |
| 23031 }, | |
| 23032 }]; | |
| 23033 })() | |
| 23034 </script> | |
| 23035 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> | |
| 23036 <template> | 23011 <template> |
| 23037 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning"> | 23012 <style> |
| 23038 :host { | 23013 :host { |
| 23039 display: block; | 23014 display: block; |
| 23040 font-family: sans-serif; | 23015 font-family: sans-serif; |
| 23041 } | 23016 } |
| 23042 #filter { | 23017 #filter { |
| 23043 margin:0 5px; | 23018 margin:0 5px; |
| 23044 } | 23019 } |
| 23045 | 23020 |
| 23046 .container { | 23021 .container { |
| 23047 min-height: 120px; | 23022 min-height: 120px; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 23110 margin: 2px; | 23085 margin: 2px; |
| 23111 /* See https://sites.google.com/a/google.com/skia-infrastructure/design-
docs/general-design-guidance */ | 23086 /* See https://sites.google.com/a/google.com/skia-infrastructure/design-
docs/general-design-guidance */ |
| 23112 --paper-checkbox-checked-color: black; | 23087 --paper-checkbox-checked-color: black; |
| 23113 --paper-checkbox-checked-ink-color: black; | 23088 --paper-checkbox-checked-ink-color: black; |
| 23114 --paper-checkbox-unchecked-color: black; | 23089 --paper-checkbox-unchecked-color: black; |
| 23115 --paper-checkbox-unchecked-ink-color: black; | 23090 --paper-checkbox-unchecked-ink-color: black; |
| 23116 --paper-checkbox-label-color: black; | 23091 --paper-checkbox-label-color: black; |
| 23117 } | 23092 } |
| 23118 </style> | 23093 </style> |
| 23119 | 23094 |
| 23120 <url-param name="filters" value="{{_filters}}" default_values="[]" multi=""> | 23095 </template> |
| 23121 </url-param> | 23096 </dom-module> |
| 23122 <url-param name="columns" value="{{columns}}" default_values="["id"
;,"os","task","status"]" multi=""> | |
| 23123 </url-param> | |
| 23124 <url-param name="query" value="{{_query}}"> | |
| 23125 </url-param> | |
| 23126 <url-param name="verbose" value="{{verbose}}"> | |
| 23127 </url-param> | |
| 23128 <url-param name="limit" default_value="200" value="{{limit}}"> | |
| 23129 </url-param> | |
| 23130 | 23097 |
| 23131 <div class="container horizontal layout"> | 23098 <script> |
| 23132 | |
| 23133 | |
| 23134 <div class="narrow-down-selector"> | |
| 23135 <div> | |
| 23136 <paper-input id="filter" label="Search columns and filters" placeholde
r="gpu nvidia" value="{{_query}}"> | |
| 23137 </paper-input> | |
| 23138 </div> | |
| 23139 | |
| 23140 <div class="selector side-by-side" title="This shows all bot dimension n
ames and other interesting bot properties. Mark the check box to add as a column
. Select the row to see filter options."> | |
| 23141 <iron-selector attr-for-selected="label" selected="{{_primarySelected}
}"> | |
| 23142 <template is="dom-repeat" items="[[_primaryItems]]" as="item"> | |
| 23143 <div class="selectable item horizontal layout" label="[[item]]"> | |
| 23144 | |
| 23145 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(ite
m,_query)]]</span>[[_afterBold(item,_query)]]</span> | |
| 23146 <span class="flex"></span> | |
| 23147 <paper-checkbox noink="" disabled$="[[_cantToggleColumn(item)]]"
checked="[[_columnState(item,columns.*)]]" on-change="_toggleColumn"> | |
| 23148 </paper-checkbox> | |
| 23149 </div> | |
| 23150 </template> | |
| 23151 </iron-selector> | |
| 23152 </div> | |
| 23153 | |
| 23154 <div class="selector side-by-side" title="These are all options (if any)
that the bot list can be filtered on."> | |
| 23155 <template is="dom-repeat" id="secondaryList" items="[[_secondaryItems]
]" as="item"> | |
| 23156 <div class="item horizontal layout" label="[[item]]"> | |
| 23157 | |
| 23158 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(item,
_query)]]</span>[[_afterBold(item,_query)]]</span> | |
| 23159 <span class="flex"></span> | |
| 23160 <iron-icon class="icons" icon="icons:arrow-forward" hidden="[[_can
tAddFilter(_primarySelected,item,_filters.*)]]" on-tap="_addFilter"> | |
| 23161 </iron-icon> | |
| 23162 </div> | |
| 23163 </template> | |
| 23164 </div> | |
| 23165 | |
| 23166 <div class="selector side-by-side" title="These filters are AND'd togeth
er and applied to all bots in | |
| 23167 the fleet."> | |
| 23168 <template is="dom-repeat" items="[[_filters]]" as="fil"> | |
| 23169 <div class="item horizontal layout" label="[[fil]]"> | |
| 23170 <span>[[fil]]</span> | |
| 23171 <span class="flex"></span> | |
| 23172 <iron-icon class="icons" icon="icons:remove-circle-outline" hidden
="[[_cantRemoveFilter(fil,_filters.*)]]" on-tap="_removeFilter"> | |
| 23173 </iron-icon> | |
| 23174 </div> | |
| 23175 </template> | |
| 23176 </div> | |
| 23177 | |
| 23178 <div class="side-by-side"> | |
| 23179 <paper-checkbox checked="{{verbose}}">Verbose Entries</paper-checkbox> | |
| 23180 <paper-input id="limit" label="Limit Results" auto-validate="" min="0"
max="1000" pattern="[0-9]+" value="{{limit}}"> | |
| 23181 </paper-input> | |
| 23182 </div> | |
| 23183 </div> | |
| 23184 | |
| 23185 </div> | |
| 23186 | |
| 23187 </template> | |
| 23188 <script> | |
| 23189 (function(){ | 23099 (function(){ |
| 23190 var FILTER_SEP = ":"; | |
| 23191 // filterMap is a map of primary -> function. The function returns a | |
| 23192 // boolean "does the bot (first arg) match the second argument". These | |
| 23193 // functions will have "this" be the botlist, and will have access to all | |
| 23194 // functions defined in bot-list and bot-list-shared. If there is not | |
| 23195 // one provided, a default will be used, see _makeFilter(). | |
| 23196 var filterMap = { | |
| 23197 android_devices: function(bot, num) { | |
| 23198 var o = this._attribute(bot, "android_devices", "0"); | |
| 23199 return o.indexOf(num) !== -1; | |
| 23200 }, | |
| 23201 device_os: function(bot, os) { | |
| 23202 var o = this._attribute(bot, "device_os", "none"); | |
| 23203 return o.indexOf(os) !== -1; | |
| 23204 }, | |
| 23205 device_type: function(bot, dt) { | |
| 23206 var o = this._attribute(bot, "device_type", "none"); | |
| 23207 return o.indexOf(this._unalias(dt)) !== -1; | |
| 23208 }, | |
| 23209 disk_space: function(bot, space) { | |
| 23210 return true; | |
| 23211 }, | |
| 23212 gpu: function(bot, gpu) { | |
| 23213 var o = this._attribute(bot, "gpu", "none"); | |
| 23214 return o.indexOf(this._unalias(gpu)) !== -1; | |
| 23215 }, | |
| 23216 id: function(bot, id) { | |
| 23217 return true; | |
| 23218 }, | |
| 23219 status: function(bot, status) { | |
| 23220 if (status === "quarantined") { | |
| 23221 return bot.quarantined; | |
| 23222 } else if (status === "dead") { | |
| 23223 return bot.is_dead; | |
| 23224 } else { | |
| 23225 // Status must be "alive". | |
| 23226 return !bot.quarantined && !bot.is_dead; | |
| 23227 } | |
| 23228 }, | |
| 23229 task: function(bot, task) { | |
| 23230 if (task === "idle") { | |
| 23231 return this._taskId(bot) === "idle"; | |
| 23232 } | |
| 23233 // Task must be "busy". | |
| 23234 return this._taskId(bot) !== "idle"; | |
| 23235 } | |
| 23236 }; | |
| 23237 | |
| 23238 // Given a space separated list of queries, matchPartCaseInsensitive | 23100 // Given a space separated list of queries, matchPartCaseInsensitive |
| 23239 // returns an object of any query that matches a part of str, case | 23101 // returns an object of any query that matches a part of str, case |
| 23240 // insensitive. The object has an idx (index) and the part that matched. | 23102 // insensitive. The object has an idx (index) and the part that matched. |
| 23241 var matchPartCaseInsensitive = function(str, queries) { | 23103 var matchPartCaseInsensitive = function(str, queries) { |
| 23242 if (!queries) { | 23104 if (!queries) { |
| 23243 return { | 23105 return { |
| 23244 idx: 0, | 23106 idx: 0, |
| 23245 part: "", | 23107 part: "", |
| 23246 }; | 23108 }; |
| 23247 } | 23109 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23260 idx: idx, | 23122 idx: idx, |
| 23261 part: xq[i], | 23123 part: xq[i], |
| 23262 }; | 23124 }; |
| 23263 } | 23125 } |
| 23264 } | 23126 } |
| 23265 return { | 23127 return { |
| 23266 idx: -1, | 23128 idx: -1, |
| 23267 }; | 23129 }; |
| 23268 }; | 23130 }; |
| 23269 | 23131 |
| 23270 Polymer({ | 23132 // Extend the Aliases behavior |
| 23271 is: "bot-filters", | 23133 SwarmingBehaviors.QueryColumnFilter = [SwarmingBehaviors.Aliases, { |
| 23272 | |
| 23273 behaviors: [SwarmingBehaviors.BotListBehavior], | |
| 23274 | 23134 |
| 23275 properties: { | 23135 properties: { |
| 23276 // input | 23136 // input |
| 23277 primary_map: { | 23137 primary_map: { |
| 23278 type: Object, | 23138 type: Object, |
| 23279 }, | 23139 }, |
| 23280 primary_arr: { | 23140 primary_arr: { |
| 23281 type: Array, | 23141 type: Array, |
| 23282 }, | 23142 }, |
| 23283 dimensions: { | 23143 dimensions: { |
| 23284 type: Array, | 23144 type: Array, |
| 23285 }, | 23145 }, |
| 23286 | |
| 23287 // output | 23146 // output |
| 23288 columns: { | |
| 23289 type: Array, | |
| 23290 notify: true, | |
| 23291 }, | |
| 23292 filter: { | 23147 filter: { |
| 23293 type: Function, | 23148 type: Function, |
| 23294 computed: "_makeFilter(_filters.*)", | 23149 computed: "_makeFilter(_filters.*)", |
| 23295 notify: true, | 23150 notify: true, |
| 23296 }, | 23151 }, |
| 23297 query_params: { | |
| 23298 type: Object, | |
| 23299 computed: "_extractQueryParams(dimensions.*,_filters.*, limit)", | |
| 23300 notify: true, | |
| 23301 }, | |
| 23302 verbose: { | |
| 23303 type: Boolean, | |
| 23304 notify: true, | |
| 23305 }, | |
| 23306 | 23152 |
| 23307 // private | 23153 // private |
| 23154 FILTER_SEP: { |
| 23155 type:String, |
| 23156 value: ":", |
| 23157 }, |
| 23308 _filters: { | 23158 _filters: { |
| 23309 type:Array, | 23159 type:Array, |
| 23310 }, | 23160 }, |
| 23311 _limit: { | 23161 _limit: { |
| 23312 type: Number, | 23162 type: Number, |
| 23313 }, | 23163 }, |
| 23314 _primaryItems: { | 23164 _primaryItems: { |
| 23315 type: Array, | 23165 type: Array, |
| 23316 computed: "_primary(_query, primary_map, primary_arr, columns.*)", | 23166 computed: "_primary(_query, primary_map, primary_arr, columns.*)", |
| 23317 }, | 23167 }, |
| 23318 _primarySelected: { | 23168 _primarySelected: { |
| 23319 type: String, | 23169 type: String, |
| 23320 value: "", | 23170 value: "", |
| 23321 }, | 23171 }, |
| 23322 // query is treated as a space separated list. | 23172 // query is treated as a space separated list. |
| 23323 _query: { | 23173 _query: { |
| 23324 type:String, | 23174 type:String, |
| 23325 }, | 23175 }, |
| 23326 _secondaryItems: { | 23176 _secondaryItems: { |
| 23327 type: Array, | 23177 type: Array, |
| 23328 computed: "_secondary(_primarySelected, _query, primary_map)", | 23178 computed: "_secondary(_primarySelected, _query, primary_map)", |
| 23329 }, | 23179 }, |
| 23180 }, |
| 23330 | 23181 |
| 23331 }, | |
| 23332 | 23182 |
| 23333 _addFilter: function(e) { | 23183 _addFilter: function(e) { |
| 23334 // e.model.foo is a way to get access to the "foo" inside a dom-repeat | 23184 // e.model.foo is a way to get access to the "foo" inside a dom-repeat |
| 23335 // that had the event (in our case, a tap) acted upon it. This name, | 23185 // that had the event (in our case, a tap) acted upon it. This name, |
| 23336 // "foo", is set by the dom-repeat above 'as="foo"' | 23186 // "foo", is set by the dom-repeat above 'as="foo"' |
| 23337 var filterItem = e.model.item; | 23187 var filterItem = e.model.item; |
| 23338 if (this._cantAddFilter(this._primarySelected, filterItem)) { | 23188 if (this._cantAddFilter(this._primarySelected, filterItem)) { |
| 23339 return; | 23189 return; |
| 23340 } | 23190 } |
| 23341 var filter = this._primarySelected + FILTER_SEP + filterItem; | 23191 var filter = this._primarySelected + this.FILTER_SEP + filterItem; |
| 23342 this.push("_filters", filter); | 23192 this.push("_filters", filter); |
| 23343 }, | 23193 }, |
| 23344 | 23194 |
| 23345 _removeFilter: function(e){ | 23195 _removeFilter: function(e){ |
| 23346 var filter = e.model.fil; | 23196 var filter = e.model.fil; |
| 23347 if (this._cantRemoveFilter(filter)){ | 23197 if (this._cantRemoveFilter(filter)){ |
| 23348 return; | 23198 return; |
| 23349 } | 23199 } |
| 23350 var idx = this._filters.indexOf(filter); | 23200 var idx = this._filters.indexOf(filter); |
| 23351 if (idx !== -1) { | 23201 if (idx !== -1) { |
| 23352 this.splice("_filters", idx, 1); | 23202 this.splice("_filters", idx, 1); |
| 23353 } | 23203 } |
| 23354 }, | 23204 }, |
| 23355 | 23205 |
| 23356 _cantAddFilter: function(primarySelected, filterItem) { | 23206 _cantAddFilter: function(primarySelected, filterItem) { |
| 23357 // Check that everything is selected and this filter isn't already in | 23207 // Check that everything is selected and this filter isn't already in |
| 23358 // the array. | 23208 // the array. |
| 23359 if (!primarySelected || !filterItem) { | 23209 if (!primarySelected || !filterItem) { |
| 23360 return true; | 23210 return true; |
| 23361 } | 23211 } |
| 23362 var filter = primarySelected + FILTER_SEP + filterItem; | 23212 var filter = primarySelected + this.FILTER_SEP + filterItem; |
| 23363 return this._filters.indexOf(filter) !== -1; | 23213 return this._filters.indexOf(filter) !== -1; |
| 23364 }, | 23214 }, |
| 23365 | 23215 |
| 23366 _cantRemoveFilter: function(filter) { | 23216 _cantRemoveFilter: function(filter) { |
| 23367 return !filter || this._filters.indexOf(filter) === -1; | 23217 return !filter || this._filters.indexOf(filter) === -1; |
| 23368 }, | 23218 }, |
| 23369 | 23219 |
| 23370 _toggleColumn: function(e) { | |
| 23371 var col = e.model.item; | |
| 23372 | |
| 23373 if (this._cantToggleColumn(col)) { | |
| 23374 return; | |
| 23375 } | |
| 23376 if (this._columnState(col)) { | |
| 23377 var idx = this.columns.indexOf(col); | |
| 23378 if (idx !== -1) { | |
| 23379 this.splice("columns", idx, 1); | |
| 23380 } | |
| 23381 return; | |
| 23382 } | |
| 23383 this.push("columns", col); | |
| 23384 }, | |
| 23385 | |
| 23386 _cantToggleColumn: function(col) { | |
| 23387 // Don't allow the id column to be removed, as the bot list is basically | |
| 23388 // meaningless without it. | |
| 23389 return !col || col === "id" ; | |
| 23390 }, | |
| 23391 | |
| 23392 _columnState: function(col) { | |
| 23393 if (!col) { | |
| 23394 return false; | |
| 23395 } | |
| 23396 return this.columns.indexOf(col) !== -1; | |
| 23397 }, | |
| 23398 | |
| 23399 _makeFilter: function() { | 23220 _makeFilter: function() { |
| 23400 // All filters will be AND'd together. | 23221 // All filters will be AND'd together. |
| 23401 // filterGroups will be a map of primary (i.e. column) -> array of | 23222 // filterGroups will be a map of primary (i.e. column) -> array of |
| 23402 // options that should be filtered to. | 23223 // options that should be filtered to. |
| 23403 // e.g. "os" -> ["Windows", "Linux"] | 23224 // e.g. "os" -> ["Windows", "Linux"] |
| 23404 // Since they will be or'd together, order doesn't matter. | 23225 // Since they will be or'd together, order doesn't matter. |
| 23405 var filterGroups = {}; | 23226 var filterGroups = {}; |
| 23406 this._filters.forEach(function(filterString){ | 23227 this._filters.forEach(function(filterString){ |
| 23407 var idx = filterString.indexOf(FILTER_SEP); | 23228 var idx = filterString.indexOf(this.FILTER_SEP); |
| 23408 var primary = filterString.slice(0, idx); | 23229 var primary = filterString.slice(0, idx); |
| 23409 var param = filterString.slice(idx + FILTER_SEP.length); | 23230 var param = filterString.slice(idx + this.FILTER_SEP.length); |
| 23410 var arr = filterGroups[primary] || []; | 23231 var arr = filterGroups[primary] || []; |
| 23411 arr.push(param); | 23232 arr.push(param); |
| 23412 filterGroups[primary] = arr; | 23233 filterGroups[primary] = arr; |
| 23413 }); | 23234 }.bind(this)); |
| 23235 var filterMap = this._filterMap || {}; |
| 23414 return function(bot){ | 23236 return function(bot){ |
| 23415 var retVal = true; | 23237 var retVal = true; |
| 23416 // Look up all the primary keys we are filter by, then look up how | 23238 // Look up all the primary keys we are filter by, then look up how |
| 23417 // to filter (in filterMap) and apply the filter for each filter | 23239 // to filter (in filterMap) and apply the filter for each filter |
| 23418 // option. | 23240 // option. |
| 23419 for (primary in filterGroups){ | 23241 for (primary in filterGroups){ |
| 23420 var params = filterGroups[primary]; | 23242 var params = filterGroups[primary]; |
| 23421 var filter = filterMap[primary]; | 23243 var filter = filterMap[primary]; |
| 23422 if (!filter) { | 23244 if (!filter) { |
| 23423 filter = function(bot, c) { | 23245 filter = function(bot, c) { |
| 23424 var o = this._attribute(bot, primary); | 23246 var o = this._attribute(bot, primary); |
| 23425 return o.indexOf(c) !== -1; | 23247 return o.indexOf(c) !== -1; |
| 23426 }.bind(this); | 23248 }.bind(this); |
| 23427 } | 23249 } |
| 23428 if (filter) { | 23250 if (filter) { |
| 23429 params.forEach(function(param){ | 23251 params.forEach(function(param){ |
| 23430 retVal = retVal && filter.bind(this)(bot,param); | 23252 retVal = retVal && filter.bind(this)(bot,param); |
| 23431 }.bind(this)); | 23253 }.bind(this)); |
| 23432 } | 23254 } |
| 23433 } | 23255 } |
| 23434 return retVal; | 23256 return retVal; |
| 23435 } | 23257 } |
| 23436 }, | 23258 }, |
| 23437 | 23259 |
| 23260 _toggleColumn: function(e) { |
| 23261 var col = e.model.item; |
| 23262 |
| 23263 if (this._cantToggleColumn(col)) { |
| 23264 return; |
| 23265 } |
| 23266 if (this._columnState(col)) { |
| 23267 var idx = this.columns.indexOf(col); |
| 23268 if (idx !== -1) { |
| 23269 this.splice("columns", idx, 1); |
| 23270 } |
| 23271 return; |
| 23272 } |
| 23273 this.push("columns", col); |
| 23274 }, |
| 23275 |
| 23276 _cantToggleColumn: function(col) { |
| 23277 // Clients can override this |
| 23278 return false; |
| 23279 }, |
| 23280 |
| 23281 _columnState: function(col) { |
| 23282 if (!col) { |
| 23283 return false; |
| 23284 } |
| 23285 return this.columns.indexOf(col) !== -1; |
| 23286 }, |
| 23287 |
| 23288 |
| 23438 _primary: function(query, primary_map, primary_arr) { | 23289 _primary: function(query, primary_map, primary_arr) { |
| 23439 // If the user has typed in a query, only show those primary keys that | 23290 // If the user has typed in a query, only show those primary keys that |
| 23440 // partially match the query or that have secondary values which | 23291 // partially match the query or that have secondary values which |
| 23441 // partially match. | 23292 // partially match. |
| 23442 var arr = this.primary_arr.filter(function(s){ | 23293 var arr = this.primary_arr.filter(function(s){ |
| 23443 if (matchPartCaseInsensitive(s, query).idx !== -1) { | 23294 if (matchPartCaseInsensitive(s, query).idx !== -1) { |
| 23444 return true; | 23295 return true; |
| 23445 } | 23296 } |
| 23446 var opts = primary_map[s]; | 23297 var opts = primary_map[s]; |
| 23447 for (var i = 0; i < opts.length; i++) { | 23298 for (var i = 0; i < opts.length; i++) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 23513 }, | 23364 }, |
| 23514 | 23365 |
| 23515 _afterBold: function(item, query) { | 23366 _afterBold: function(item, query) { |
| 23516 var match = matchPartCaseInsensitive(item, query); | 23367 var match = matchPartCaseInsensitive(item, query); |
| 23517 if (match.idx === -1) { | 23368 if (match.idx === -1) { |
| 23518 return ""; | 23369 return ""; |
| 23519 } | 23370 } |
| 23520 return item.substring(match.idx + match.part.length); | 23371 return item.substring(match.idx + match.part.length); |
| 23521 }, | 23372 }, |
| 23522 | 23373 |
| 23374 // Common filters shared between tasklist and botlist |
| 23375 _commonFilters: function() { |
| 23376 // return a fresh object so all elements have their own copy |
| 23377 return { |
| 23378 android_devices: function(bot, num) { |
| 23379 var o = this._attribute(bot, "android_devices", "0"); |
| 23380 return o.indexOf(num) !== -1; |
| 23381 }, |
| 23382 device_os: function(bot, os) { |
| 23383 var o = this._attribute(bot, "device_os", "none"); |
| 23384 return o.indexOf(os) !== -1; |
| 23385 }, |
| 23386 device_type: function(bot, dt) { |
| 23387 var o = this._attribute(bot, "device_type", "none"); |
| 23388 return o.indexOf(this._unalias(dt)) !== -1; |
| 23389 }, |
| 23390 gpu: function(bot, gpu) { |
| 23391 var o = this._attribute(bot, "gpu", "none"); |
| 23392 return o.indexOf(this._unalias(gpu)) !== -1; |
| 23393 }, |
| 23394 }; |
| 23395 }, |
| 23396 |
| 23397 }]; |
| 23398 })(); |
| 23399 </script> |
| 23400 <script> |
| 23401 (function(){ |
| 23402 // Taken from http://developer.android.com/reference/android/os/BatteryManag
er.html |
| 23403 var BATTERY_HEALTH_UNKNOWN = 1; |
| 23404 var BATTERY_HEALTH_GOOD = 2; |
| 23405 var BATTERY_STATUS_CHARGING = 2; |
| 23406 |
| 23407 var UNAUTHENTICATED = "unauthenticated"; |
| 23408 var AVAILABLE = "available"; |
| 23409 var UNKNOWN = "unknown"; |
| 23410 |
| 23411 // This behavior wraps up all the shared bot-list functionality by |
| 23412 // extending SwarmingBehaviors.SwarmingBehavior |
| 23413 SwarmingBehaviors.BotListBehavior = [SwarmingBehaviors.SwarmingBehavior, { |
| 23414 |
| 23415 properties: { |
| 23416 BOT_PROPERTIES: { |
| 23417 type: Array, |
| 23418 value: function() { |
| 23419 // TODO(kjlubick): Add more of these things from state, as they |
| 23420 // needed/useful/requested. |
| 23421 return ["disk_space", "task", "status"]; |
| 23422 } |
| 23423 }, |
| 23424 }, |
| 23425 |
| 23426 // _attribute looks first in dimension and then in state for the |
| 23427 // specified attribute. This will always return an array. If there is |
| 23428 // no matching attribute, ["unknown"] will be returned. |
| 23429 _attribute: function(bot, attr, none) { |
| 23430 none = none || UNKNOWN; |
| 23431 return this._dimension(bot, attr) || this._state(bot, attr) || [none]; |
| 23432 }, |
| 23433 |
| 23434 _devices: function(bot) { |
| 23435 var devices = []; |
| 23436 var d = (bot && bot.state && bot.state.devices) || {}; |
| 23437 // state.devices is like {Serial:Object}, so we need to keep the serial |
| 23438 for (key in d) { |
| 23439 var o = d[key]; |
| 23440 o.serial = key; |
| 23441 o.okay = (o.state === AVAILABLE); |
| 23442 // It is easier to assume all devices on a bot are of the same type |
| 23443 // than to pick through the (incomplete) device state and find it. |
| 23444 o.device_type = this._attribute(bot, "device_type")[0]; |
| 23445 devices.push(o); |
| 23446 } |
| 23447 return devices; |
| 23448 }, |
| 23449 |
| 23450 // _deviceType returns the codename of a given Android device. |
| 23451 _deviceType: function(device) { |
| 23452 return device.device_type.toLowerCase(); |
| 23453 }, |
| 23454 |
| 23455 // _dimension returns the given dimension of a bot. If it is defined, it |
| 23456 // is an array of strings. |
| 23457 _dimension: function(bot, dim) { |
| 23458 if (!bot || !bot.dimensions || !dim) { |
| 23459 return undefined; |
| 23460 } |
| 23461 for (var i = 0; i < bot.dimensions.length; i++) { |
| 23462 if (bot.dimensions[i].key === dim) { |
| 23463 return bot.dimensions[i].value; |
| 23464 } |
| 23465 } |
| 23466 return undefined; |
| 23467 }, |
| 23468 |
| 23469 // _state returns the requested attribute from a bot's state. |
| 23470 // For consistency with _dimension, if the attribute is not an array, |
| 23471 // it is put as the only element in an array. |
| 23472 _state: function(bot, attr) { |
| 23473 if (!bot || !bot.state || !bot.state[attr]) { |
| 23474 return undefined |
| 23475 } |
| 23476 var state = bot.state[attr]; |
| 23477 if (Array.isArray(state)) { |
| 23478 return state; |
| 23479 } |
| 23480 return [state]; |
| 23481 }, |
| 23482 |
| 23483 _taskId: function(bot) { |
| 23484 if (bot && bot.task_id) { |
| 23485 return bot.task_id; |
| 23486 } |
| 23487 return "idle"; |
| 23488 }, |
| 23489 |
| 23490 }]; |
| 23491 })() |
| 23492 </script> |
| 23493 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> |
| 23494 <template> |
| 23495 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning query-column-filter-style"> |
| 23496 |
| 23497 </style> |
| 23498 |
| 23499 <url-param name="filters" value="{{_filters}}" default_values="[]" multi=""> |
| 23500 </url-param> |
| 23501 <url-param name="columns" value="{{columns}}" default_values="["id"
;,"os","task","status"]" multi=""> |
| 23502 </url-param> |
| 23503 <url-param name="query" value="{{_query}}" default_value=""> |
| 23504 </url-param> |
| 23505 <url-param name="verbose" value="{{verbose}}"> |
| 23506 </url-param> |
| 23507 <url-param name="limit" default_value="200" value="{{limit}}"> |
| 23508 </url-param> |
| 23509 |
| 23510 <div class="container horizontal layout"> |
| 23511 |
| 23512 |
| 23513 <div class="narrow-down-selector"> |
| 23514 <div> |
| 23515 <paper-input id="filter" label="Search columns and filters" placeholde
r="gpu nvidia" value="{{_query}}"> |
| 23516 </paper-input> |
| 23517 </div> |
| 23518 |
| 23519 <div class="selector side-by-side" title="This shows all bot dimension n
ames and other interesting bot properties. Mark the check box to add as a column
. Select the row to see filter options."> |
| 23520 <iron-selector attr-for-selected="label" selected="{{_primarySelected}
}"> |
| 23521 <template is="dom-repeat" items="[[_primaryItems]]" as="item"> |
| 23522 <div class="selectable item horizontal layout" label="[[item]]"> |
| 23523 |
| 23524 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(ite
m,_query)]]</span>[[_afterBold(item,_query)]]</span> |
| 23525 <span class="flex"></span> |
| 23526 <paper-checkbox noink="" disabled$="[[_cantToggleColumn(item)]]"
checked="[[_columnState(item,columns.*)]]" on-change="_toggleColumn"> |
| 23527 </paper-checkbox> |
| 23528 </div> |
| 23529 </template> |
| 23530 </iron-selector> |
| 23531 </div> |
| 23532 |
| 23533 <div class="selector side-by-side" title="These are all options (if any)
that the bot list can be filtered on."> |
| 23534 <template is="dom-repeat" id="secondaryList" items="[[_secondaryItems]
]" as="item"> |
| 23535 <div class="item horizontal layout" label="[[item]]"> |
| 23536 |
| 23537 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(item,
_query)]]</span>[[_afterBold(item,_query)]]</span> |
| 23538 <span class="flex"></span> |
| 23539 <iron-icon class="icons" icon="icons:arrow-forward" hidden="[[_can
tAddFilter(_primarySelected,item,_filters.*)]]" on-tap="_addFilter"> |
| 23540 </iron-icon> |
| 23541 </div> |
| 23542 </template> |
| 23543 </div> |
| 23544 |
| 23545 <div class="selector side-by-side" title="These filters are AND'd togeth
er and applied to all bots in |
| 23546 the fleet."> |
| 23547 <template is="dom-repeat" items="[[_filters]]" as="fil"> |
| 23548 <div class="item horizontal layout" label="[[fil]]"> |
| 23549 <span>[[fil]]</span> |
| 23550 <span class="flex"></span> |
| 23551 <iron-icon class="icons" icon="icons:remove-circle-outline" hidden
="[[_cantRemoveFilter(fil,_filters.*)]]" on-tap="_removeFilter"> |
| 23552 </iron-icon> |
| 23553 </div> |
| 23554 </template> |
| 23555 </div> |
| 23556 |
| 23557 <div class="side-by-side"> |
| 23558 <paper-checkbox checked="{{verbose}}">Verbose Entries</paper-checkbox> |
| 23559 <paper-input id="limit" label="Limit Results" auto-validate="" min="0"
max="1000" pattern="[0-9]+" value="{{limit}}"> |
| 23560 </paper-input> |
| 23561 </div> |
| 23562 </div> |
| 23563 |
| 23564 </div> |
| 23565 |
| 23566 </template> |
| 23567 <script> |
| 23568 (function(){ |
| 23569 // See query-column-filter for more documentation on these properties. |
| 23570 var filterMap = { |
| 23571 disk_space: function(bot, space) { |
| 23572 return true; |
| 23573 }, |
| 23574 id: function(bot, id) { |
| 23575 return true; |
| 23576 }, |
| 23577 status: function(bot, status) { |
| 23578 if (status === "quarantined") { |
| 23579 return bot.quarantined; |
| 23580 } else if (status === "dead") { |
| 23581 return bot.is_dead; |
| 23582 } else { |
| 23583 // Status must be "alive". |
| 23584 return !bot.quarantined && !bot.is_dead; |
| 23585 } |
| 23586 }, |
| 23587 task: function(bot, task) { |
| 23588 if (task === "idle") { |
| 23589 return this._taskId(bot) === "idle"; |
| 23590 } |
| 23591 // Task must be "busy". |
| 23592 return this._taskId(bot) !== "idle"; |
| 23593 } |
| 23594 }; |
| 23595 |
| 23596 Polymer({ |
| 23597 is: "bot-filters", |
| 23598 |
| 23599 behaviors: [ |
| 23600 SwarmingBehaviors.BotListBehavior, |
| 23601 SwarmingBehaviors.QueryColumnFilter, |
| 23602 ], |
| 23603 |
| 23604 properties: { |
| 23605 // url-param doesn't like columns to be defined in query_column-filter, |
| 23606 // so we define it here. |
| 23607 columns: { |
| 23608 type: Array, |
| 23609 notify: true, |
| 23610 }, |
| 23611 query_params: { |
| 23612 type: Object, |
| 23613 computed: "_extractQueryParams(dimensions.*,_filters.*, limit)", |
| 23614 notify: true, |
| 23615 }, |
| 23616 verbose: { |
| 23617 type: Boolean, |
| 23618 notify: true, |
| 23619 }, |
| 23620 |
| 23621 // for QueryColumnFilter |
| 23622 _filterMap: { |
| 23623 type: Object, |
| 23624 value: function() { |
| 23625 var base = this._commonFilters(); |
| 23626 for (var attr in filterMap) { |
| 23627 base[attr] = filterMap[attr]; |
| 23628 } |
| 23629 return base; |
| 23630 }, |
| 23631 } |
| 23632 }, |
| 23633 |
| 23634 _cantToggleColumn: function(col) { |
| 23635 // Don't allow the id column to be removed, as the bot list is basically |
| 23636 // meaningless without it. |
| 23637 return !col || col === "id" ; |
| 23638 }, |
| 23639 |
| 23523 _extractQueryParams: function() { | 23640 _extractQueryParams: function() { |
| 23524 var params = {}; | 23641 var params = {}; |
| 23525 var dims = []; | 23642 var dims = []; |
| 23526 this._filters.forEach(function(f) { | 23643 this._filters.forEach(function(f) { |
| 23527 var split = f.split(FILTER_SEP, 1) | 23644 var split = f.split(this.FILTER_SEP, 1) |
| 23528 var col = split[0]; | 23645 var col = split[0]; |
| 23529 if (this.dimensions.indexOf(col) !== -1) { | 23646 if (this.dimensions.indexOf(col) !== -1) { |
| 23530 var rest = f.substring(col.length + FILTER_SEP.length); | 23647 var rest = f.substring(col.length + this.FILTER_SEP.length); |
| 23531 dims.push(col + FILTER_SEP + this._unalias(rest)) | 23648 dims.push(col + this.FILTER_SEP + this._unalias(rest)) |
| 23532 } else if (col === "status") { | 23649 } else if (col === "status") { |
| 23533 var rest = f.substring(col.length + FILTER_SEP.length); | 23650 var rest = f.substring(col.length + this.FILTER_SEP.length); |
| 23534 if (rest === "alive") { | 23651 if (rest === "alive") { |
| 23535 params["is_dead"] = "FALSE"; | 23652 params["is_dead"] = "FALSE"; |
| 23536 params["quarantined"] = "FALSE"; | 23653 params["quarantined"] = "FALSE"; |
| 23537 } else if (rest === "quarantined") { | 23654 } else if (rest === "quarantined") { |
| 23538 params["quarantined"] = "TRUE"; | 23655 params["quarantined"] = "TRUE"; |
| 23539 } else if (rest === "dead") { | 23656 } else if (rest === "dead") { |
| 23540 params["is_dead"] = "TRUE"; | 23657 params["is_dead"] = "TRUE"; |
| 23541 } | 23658 } |
| 23542 } | 23659 } |
| 23543 }.bind(this)); | 23660 }.bind(this)); |
| 23544 params["dimensions"] = dims; | 23661 params["dimensions"] = dims; |
| 23545 var lim = Math.floor(this.limit) | 23662 var lim = Math.floor(this.limit) |
| 23546 if (Number.isInteger(lim)) { | 23663 if (Number.isInteger(lim)) { |
| 23547 // Clamp the limit | 23664 // Clamp the limit |
| 23548 lim = Math.max(lim, 1); | 23665 lim = Math.max(lim, 1); |
| 23549 lim = Math.min(1000, lim); | 23666 lim = Math.min(1000, lim); |
| 23550 params["limit"] = lim; | 23667 params["limit"] = lim; |
| 23551 // not !-- because limit could be "900" | 23668 // not !== because limit could be a string, e.g. "900" |
| 23552 if (this.limit != lim) { | 23669 if (this.limit != lim) { |
| 23553 this.set("limit", lim); | 23670 this.set("limit", lim); |
| 23554 } | 23671 } |
| 23555 } | 23672 } |
| 23556 return params; | 23673 return params; |
| 23557 } | 23674 } |
| 23558 | 23675 |
| 23559 }); | 23676 }); |
| 23560 })(); | 23677 })(); |
| 23561 </script> | 23678 </script> |
| 23562 </dom-module><dom-module id="bot-list-data" assetpath="/res/imp/botlist/"> | 23679 </dom-module><dom-module id="bot-list-data" assetpath="/res/imp/botlist/"> |
| 23563 <template> | 23680 <template> |
| 23564 <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth
_headers]]" params="[[query_params]]" handle-as="json" last-response="{{_list}}"
loading="{{_busy1}}"> | 23681 <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth
_headers]]" params="[[query_params]]" handle-as="json" last-response="{{_list}}"
loading="{{_busy1}}"> |
| 23565 </iron-ajax> | 23682 </iron-ajax> |
| 23566 | 23683 |
| 23567 <iron-ajax id="dimensions" url="/_ah/api/swarming/v1/bots/dimensions" header
s="[[auth_headers]]" handle-as="json" last-response="{{_dimensions}}" loading="{
{_busy2}}"> | 23684 <iron-ajax id="dimensions" url="/_ah/api/swarming/v1/bots/dimensions" header
s="[[auth_headers]]" handle-as="json" last-response="{{_dimensions}}" loading="{
{_busy2}}"> |
| 23568 </iron-ajax> | 23685 </iron-ajax> |
| 23569 | 23686 |
| 23570 <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_
headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy3}}"> | 23687 <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_
headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy3}}"> |
| 23571 </iron-ajax> | 23688 </iron-ajax> |
| 23572 </template> | 23689 </template> |
| 23573 <script> | 23690 <script> |
| 23574 (function(){ | 23691 (function(){ |
| 23575 var BLACKLIST_DIMENSIONS = ["quarantined", "error"]; | 23692 var BLACKLIST_DIMENSIONS = ["quarantined", "error"]; |
| 23576 | 23693 |
| 23577 Polymer({ | 23694 Polymer({ |
| 23578 is: 'bot-list-data', | 23695 is: 'bot-list-data', |
| 23579 | 23696 |
| 23580 behaviors: [SwarmingBehaviors.BotListBehavior], | 23697 behaviors: [ |
| 23698 SwarmingBehaviors.BotListBehavior, |
| 23699 SwarmingBehaviors.Aliases, |
| 23700 ], |
| 23581 | 23701 |
| 23582 properties: { | 23702 properties: { |
| 23583 // inputs | 23703 // inputs |
| 23584 auth_headers: { | 23704 auth_headers: { |
| 23585 type: Object, | 23705 type: Object, |
| 23586 observer: "signIn", | 23706 observer: "signIn", |
| 23587 }, | 23707 }, |
| 23588 query_params: { | 23708 query_params: { |
| 23589 type: Object, | 23709 type: Object, |
| 23590 }, | 23710 }, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 23604 type: Array, | 23724 type: Array, |
| 23605 computed: "_makeArray(_dimensions)", | 23725 computed: "_makeArray(_dimensions)", |
| 23606 notify: true, | 23726 notify: true, |
| 23607 }, | 23727 }, |
| 23608 fleet: { | 23728 fleet: { |
| 23609 type: Object, | 23729 type: Object, |
| 23610 computed: "_fleet(_count)", | 23730 computed: "_fleet(_count)", |
| 23611 notify: true, | 23731 notify: true, |
| 23612 }, | 23732 }, |
| 23613 primary_map: { | 23733 primary_map: { |
| 23614 type:Object, | 23734 type: Object, |
| 23615 computed: "_primaryMap(_dimensions)", | 23735 computed: "_primaryMap(_dimensions)", |
| 23616 notify: true, | 23736 notify: true, |
| 23617 }, | 23737 }, |
| 23618 primary_arr: { | 23738 primary_arr: { |
| 23619 type: Array, | 23739 type: Array, |
| 23620 //BOT_PROPERTIES is inherited from BotListBehavior | 23740 //BOT_PROPERTIES is inherited from BotListBehavior |
| 23621 computed: "_primaryArr(dimensions, BOT_PROPERTIES)", | 23741 computed: "_primaryArr(dimensions, BOT_PROPERTIES)", |
| 23622 notify: true, | 23742 notify: true, |
| 23623 }, | 23743 }, |
| 23624 | 23744 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 23691 _makeArray: function(dimObj) { | 23811 _makeArray: function(dimObj) { |
| 23692 if (!dimObj || !dimObj.bots_dimensions) { | 23812 if (!dimObj || !dimObj.bots_dimensions) { |
| 23693 return []; | 23813 return []; |
| 23694 } | 23814 } |
| 23695 var dims = []; | 23815 var dims = []; |
| 23696 dimObj.bots_dimensions.forEach(function(d){ | 23816 dimObj.bots_dimensions.forEach(function(d){ |
| 23697 if (BLACKLIST_DIMENSIONS.indexOf(d.key) === -1) { | 23817 if (BLACKLIST_DIMENSIONS.indexOf(d.key) === -1) { |
| 23698 dims.push(d.key); | 23818 dims.push(d.key); |
| 23699 } | 23819 } |
| 23700 }); | 23820 }); |
| 23821 dims.push("id"); |
| 23701 dims.sort(); | 23822 dims.sort(); |
| 23702 return dims; | 23823 return dims; |
| 23703 }, | 23824 }, |
| 23704 | 23825 |
| 23705 _primaryArr: function(dimensions, properties) { | 23826 _primaryArr: function(dimensions, properties) { |
| 23706 return dimensions.concat(properties); | 23827 return dimensions.concat(properties); |
| 23707 }, | 23828 }, |
| 23708 | 23829 |
| 23709 _primaryMap: function(dimensions){ | 23830 _primaryMap: function(dimensions){ |
| 23710 // pMap will have a list of columns to available values (primary key | 23831 // pMap will have a list of columns to available values (primary key |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 24095 "device_type": "Device Type", | 24216 "device_type": "Device Type", |
| 24096 "disk_space": "Free Space (MB)", | 24217 "disk_space": "Free Space (MB)", |
| 24097 "gpu": "GPU", | 24218 "gpu": "GPU", |
| 24098 "os": "OS", | 24219 "os": "OS", |
| 24099 "pool": "Pool", | 24220 "pool": "Pool", |
| 24100 "status": "Status", | 24221 "status": "Status", |
| 24101 "xcode_version": "XCode Version", | 24222 "xcode_version": "XCode Version", |
| 24102 }; | 24223 }; |
| 24103 | 24224 |
| 24104 var columnMap = { | 24225 var columnMap = { |
| 24105 android_devices: function(bot) { | |
| 24106 var devs = this._attribute(bot, "android_devices", "0"); | |
| 24107 if (this._verbose) { | |
| 24108 return devs.join(" | ") + " devices available"; | |
| 24109 } | |
| 24110 // max() works on strings as long as they can be coerced to Number. | |
| 24111 return Math.max(...devs) + " devices available"; | |
| 24112 }, | |
| 24113 device_type: function(bot) { | |
| 24114 var dt = this._attribute(bot, "device_type", "none"); | |
| 24115 dt = dt[0]; | |
| 24116 var alias = this._androidAlias(dt); | |
| 24117 if (alias === "unknown") { | |
| 24118 return dt; | |
| 24119 } | |
| 24120 return this._applyAlias(dt, alias); | |
| 24121 }, | |
| 24122 disk_space: function(bot) { | 24226 disk_space: function(bot) { |
| 24123 var aliased = []; | 24227 var aliased = []; |
| 24124 bot.disks.forEach(function(disk){ | 24228 bot.disks.forEach(function(disk){ |
| 24125 var alias = sk.human.bytes(disk.mb, swarming.MB); | 24229 var alias = sk.human.bytes(disk.mb, swarming.MB); |
| 24126 aliased.push(this._applyAlias(disk.mb, disk.id + " "+ alias)); | 24230 aliased.push(this._applyAlias(disk.mb, disk.id + " "+ alias)); |
| 24127 }.bind(this)); | 24231 }.bind(this)); |
| 24128 if (this._verbose) { | 24232 if (this._verbose) { |
| 24129 return aliased.join(" | "); | 24233 return aliased.join(" | "); |
| 24130 } | 24234 } |
| 24131 return aliased[0]; | 24235 return aliased[0]; |
| 24132 }, | 24236 }, |
| 24133 gpu: function(bot){ | |
| 24134 var gpus = this._attribute(bot, "gpu", "none") | |
| 24135 var verbose = [] | |
| 24136 var named = []; | |
| 24137 // non-verbose mode has only the top level GPU info "e.g. NVidia" | |
| 24138 // which is found by looking for gpu ids w/o a colon. | |
| 24139 gpus.forEach(function(g){ | |
| 24140 var alias = this._gpuAlias(g); | |
| 24141 if (alias === "unknown") { | |
| 24142 verbose.push(g); | |
| 24143 if (g.indexOf(":") === -1) { | |
| 24144 named.push(g); | |
| 24145 } | |
| 24146 return; | |
| 24147 } | |
| 24148 verbose.push(this._applyAlias(g, alias)); | |
| 24149 if (g.indexOf(":") === -1) { | |
| 24150 named.push(this._applyAlias(g, alias)); | |
| 24151 } | |
| 24152 }.bind(this)) | |
| 24153 if (this._verbose) { | |
| 24154 return verbose.join(" | "); | |
| 24155 } | |
| 24156 return named.join(" | "); | |
| 24157 }, | |
| 24158 id: function(bot) { | 24237 id: function(bot) { |
| 24159 return bot.bot_id; | 24238 return bot.bot_id; |
| 24160 }, | 24239 }, |
| 24161 pool: function(bot) { | |
| 24162 var pool = this._attribute(bot, "pool"); | |
| 24163 return pool.join(" | "); | |
| 24164 }, | |
| 24165 status: function(bot) { | 24240 status: function(bot) { |
| 24166 // If a bot is both dead and quarantined, show the deadness over the | 24241 // If a bot is both dead and quarantined, show the deadness over the |
| 24167 // quarentinedness. | 24242 // quarentinedness. |
| 24168 if (bot.is_dead) { | 24243 if (bot.is_dead) { |
| 24169 return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) + | 24244 return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) + |
| 24170 " ago"; | 24245 " ago"; |
| 24171 } | 24246 } |
| 24172 if (bot.quarantined) { | 24247 if (bot.quarantined) { |
| 24173 return "Quarantined: " + this._attribute(bot, "quarantined"); | 24248 var msg = this._state(bot, "quarantined")[0]; |
| 24249 // Sometimes, the quarantined message is actually in "error". This |
| 24250 // happens when the bot code has thrown an exception. |
| 24251 if (msg === "unknown" || msg === "true" || msg === true) { |
| 24252 msg = this._attribute(bot, "error"); |
| 24253 } |
| 24254 return "Quarantined: " + msg; |
| 24174 } | 24255 } |
| 24175 return "Alive"; | 24256 return "Alive"; |
| 24176 }, | 24257 }, |
| 24177 task: function(bot){ | 24258 task: function(bot){ |
| 24178 return this._taskId(bot); | 24259 return this._taskId(bot); |
| 24179 }, | 24260 }, |
| 24180 }; | 24261 }; |
| 24181 | 24262 |
| 24182 var deviceColumnMap = { | 24263 var deviceColumnMap = { |
| 24183 android_devices: function(device) { | 24264 android_devices: function(device) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 24213 disk_space: function(dir, botA, botB) { | 24294 disk_space: function(dir, botA, botB) { |
| 24214 // We sort based on the raw number of MB of the first disk. | 24295 // We sort based on the raw number of MB of the first disk. |
| 24215 var botACol = botA.disks[0].mb; | 24296 var botACol = botA.disks[0].mb; |
| 24216 var botBCol = botB.disks[0].mb;; | 24297 var botBCol = botB.disks[0].mb;; |
| 24217 return dir * swarming.naturalCompare(botACol, botBCol); | 24298 return dir * swarming.naturalCompare(botACol, botBCol); |
| 24218 }, | 24299 }, |
| 24219 }; | 24300 }; |
| 24220 | 24301 |
| 24221 Polymer({ | 24302 Polymer({ |
| 24222 is: 'bot-list', | 24303 is: 'bot-list', |
| 24223 behaviors: [SwarmingBehaviors.BotListBehavior, | 24304 |
| 24224 SwarmingBehaviors.DynamicTableBehavior], | 24305 // The order behaviors are applied in matters - later ones overwrite |
| 24306 // attributes of earlier ones |
| 24307 behaviors: [ |
| 24308 SwarmingBehaviors.BotListBehavior, |
| 24309 SwarmingBehaviors.DynamicTableBehavior, |
| 24310 ], |
| 24225 | 24311 |
| 24226 properties: { | 24312 properties: { |
| 24227 client_id: { | 24313 client_id: { |
| 24228 type: String, | 24314 type: String, |
| 24229 }, | 24315 }, |
| 24230 | 24316 |
| 24231 // For dynamic table. | 24317 // For dynamic table. |
| 24232 _columnMap: { | 24318 _columnMap: { |
| 24233 type: Object, | 24319 type: Object, |
| 24234 value: columnMap, | 24320 value: function() { |
| 24321 var base = this._commonColumns(); |
| 24322 for (var attr in columnMap) { |
| 24323 base[attr] = columnMap[attr]; |
| 24324 } |
| 24325 return base; |
| 24326 }, |
| 24235 }, | 24327 }, |
| 24236 _headerMap: { | 24328 _headerMap: { |
| 24237 type: Object, | 24329 type: Object, |
| 24238 value: headerMap, | 24330 value: headerMap, |
| 24239 }, | 24331 }, |
| 24240 _specialColumns: { | 24332 _specialColumns: { |
| 24241 type: Array, | 24333 type: Array, |
| 24242 value: specialColumns, | 24334 value: specialColumns, |
| 24243 }, | 24335 }, |
| 24244 _specialSort: { | 24336 _specialSort: { |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 24533 | 24625 |
| 24534 _taskClass: function(task) { | 24626 _taskClass: function(task) { |
| 24535 // TODO(kjlubick): Color tasks? | 24627 // TODO(kjlubick): Color tasks? |
| 24536 return ""; | 24628 return ""; |
| 24537 } | 24629 } |
| 24538 | 24630 |
| 24539 }); | 24631 }); |
| 24540 })(); | 24632 })(); |
| 24541 </script> | 24633 </script> |
| 24542 </dom-module></div></body></html> | 24634 </dom-module></div></body></html> |
| OLD | NEW |