| 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 14614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14625 <dom-module id="swarming-app-style" assetpath="/res/imp/common/"> | 14625 <dom-module id="swarming-app-style" assetpath="/res/imp/common/"> |
| 14626 <style> | 14626 <style> |
| 14627 * { | 14627 * { |
| 14628 font-family: sans-serif; | 14628 font-family: sans-serif; |
| 14629 } | 14629 } |
| 14630 /* Only style anchor tags that are actually linking somewhere.*/ | 14630 /* Only style anchor tags that are actually linking somewhere.*/ |
| 14631 a[href] { | 14631 a[href] { |
| 14632 color: #1F78B4; | 14632 color: #1F78B4; |
| 14633 } | 14633 } |
| 14634 </style> | 14634 </style> |
| 14635 </dom-module><dom-module id="swarming-index" assetpath="/res/imp/index/"> | 14635 </dom-module> |
| 14636 |
| 14637 <script> |
| 14638 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; |
| 14639 (function(){ |
| 14640 // This behavior wraps up all the shared swarming functionality. |
| 14641 SwarmingBehaviors.SwarmingBehavior = { |
| 14642 |
| 14643 _not: function(a) { |
| 14644 return !a; |
| 14645 }, |
| 14646 |
| 14647 _or: function() { |
| 14648 var result = false; |
| 14649 // can't use .foreach, as arguments isn't really a function. |
| 14650 for (var i = 0; i < arguments.length; i++) { |
| 14651 result = result || arguments[i]; |
| 14652 } |
| 14653 return result; |
| 14654 }, |
| 14655 }; |
| 14656 })(); |
| 14657 </script> |
| 14658 <dom-module id="swarming-index" assetpath="/res/imp/index/"> |
| 14636 <template> | 14659 <template> |
| 14637 <style include="swarming-app-style"> | 14660 <style include="swarming-app-style"> |
| 14638 | 14661 |
| 14639 </style> | 14662 </style> |
| 14640 | 14663 |
| 14641 <swarming-app client_id="[[client_id]]" auth_headers="{{auth_headers}}" name
="Swarming" busy="[[busy]]"> | 14664 <swarming-app client_id="[[client_id]]" auth_headers="{{auth_headers}}" name
="Swarming" busy="[[busy]]"> |
| 14642 | 14665 |
| 14643 <iron-ajax id="request" url="/_ah/api/swarming/v1/server/details" headers=
"[[auth_headers]]" handle-as="json" last-response="{{serverDetails}}" loading="{
{busy}}"> | 14666 <iron-ajax id="request" url="/_ah/api/swarming/v1/server/details" headers=
"[[auth_headers]]" handle-as="json" last-response="{{serverDetails}}" loading="{
{busy}}"> |
| 14644 </iron-ajax> | 14667 </iron-ajax> |
| 14645 | 14668 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 14668 type: String, | 14691 type: String, |
| 14669 } | 14692 } |
| 14670 }, | 14693 }, |
| 14671 | 14694 |
| 14672 signIn: function(){ | 14695 signIn: function(){ |
| 14673 this.$.request.generateRequest(); | 14696 this.$.request.generateRequest(); |
| 14674 }, | 14697 }, |
| 14675 | 14698 |
| 14676 }); | 14699 }); |
| 14677 </script> | 14700 </script> |
| 14701 </dom-module><dom-module id="dynamic-table-style" assetpath="/res/imp/common/"> |
| 14702 <template> |
| 14703 <style> |
| 14704 table { |
| 14705 border-collapse: collapse; |
| 14706 margin-left: 5px; |
| 14707 } |
| 14708 td, th { |
| 14709 border: 1px solid #DDD; |
| 14710 padding: 5px; |
| 14711 } |
| 14712 th { |
| 14713 position: relative; |
| 14714 } |
| 14715 sort-toggle { |
| 14716 position: absolute; |
| 14717 right: 0; |
| 14718 top: 0.4em; |
| 14719 } |
| 14720 </style> |
| 14721 |
| 14722 </template> |
| 14678 </dom-module> | 14723 </dom-module> |
| 14679 | 14724 |
| 14680 <script> | 14725 <script> |
| 14726 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; |
| 14727 (function(){ |
| 14728 // This behavior wraps up all the shared swarming functionality. |
| 14729 SwarmingBehaviors.DynamicTableBehavior = { |
| 14730 |
| 14731 properties: { |
| 14732 |
| 14733 _columns: { |
| 14734 type: Array, |
| 14735 }, |
| 14736 |
| 14737 _filter: { |
| 14738 type: Function, |
| 14739 }, |
| 14740 |
| 14741 _filteredSortedItems: { |
| 14742 type: Array, |
| 14743 computed: "_filterAndSort(_items,_filter.*,_sort.*)" |
| 14744 }, |
| 14745 |
| 14746 _items: { |
| 14747 type: Array, |
| 14748 }, |
| 14749 |
| 14750 _plainColumns: { |
| 14751 type: Array, |
| 14752 computed: "_stripSpecial(_columns.*)", |
| 14753 }, |
| 14754 |
| 14755 // _sort is an Object {name:String, direction:String}. |
| 14756 _sort: { |
| 14757 type: Object, |
| 14758 computed: "_makeSortObject(_sortstr)", |
| 14759 }, |
| 14760 |
| 14761 _sortstr: { |
| 14762 type: String, |
| 14763 }, |
| 14764 |
| 14765 _verbose: { |
| 14766 type: Boolean, |
| 14767 } |
| 14768 }, |
| 14769 |
| 14770 _column: function(col, key) { |
| 14771 var f = this._columnMap[col]; |
| 14772 if (!f) { |
| 14773 f = function(key) { |
| 14774 var c = this._attribute(key, col, "none"); |
| 14775 if (this._verbose) { |
| 14776 return c.join(" | "); |
| 14777 } |
| 14778 return c[0]; |
| 14779 } |
| 14780 } |
| 14781 return f.bind(this)(key); |
| 14782 }, |
| 14783 |
| 14784 _compare: function(a, b) { |
| 14785 if (!this._sort) { |
| 14786 return 0; |
| 14787 } |
| 14788 var dir = 1; |
| 14789 if (this._sort.direction === "desc") { |
| 14790 dir = -1; |
| 14791 } |
| 14792 var sort = this._specialSort[this._sort.name]; |
| 14793 if (sort) { |
| 14794 return sort.bind(this)(dir, a, b); |
| 14795 } |
| 14796 // Default to a natural compare of the columns. |
| 14797 var aCol = this._column(this._sort.name, a); |
| 14798 var bCol = this._column(this._sort.name, b); |
| 14799 |
| 14800 return dir * swarming.naturalCompare(aCol, bCol); |
| 14801 }, |
| 14802 |
| 14803 _filterAndSort: function() { |
| 14804 // We intentionally sort this._items (and not a copy) to allow users to |
| 14805 // "chain" sorts, that is, sort by one thing and then another, and |
| 14806 // have both orderings properly impact the list. |
| 14807 swarming.stableSort(this._items, this._compare.bind(this)); |
| 14808 var items = this._items; |
| 14809 if (this._filter) { |
| 14810 items = items.filter(this._filter.bind(this)); |
| 14811 } |
| 14812 |
| 14813 return items; |
| 14814 }, |
| 14815 |
| 14816 _header: function(col){ |
| 14817 return this._headerMap[col] || col; |
| 14818 }, |
| 14819 |
| 14820 _hide: function(col) { |
| 14821 return this._columns.indexOf(col) === -1; |
| 14822 }, |
| 14823 |
| 14824 _makeSortObject: function(sortstr){ |
| 14825 if (!sortstr) { |
| 14826 return undefined; |
| 14827 } |
| 14828 var pieces = sortstr.split(":"); |
| 14829 if (pieces.length != 2) { |
| 14830 // fail safe |
| 14831 return {name: "id", direction: "asc"}; |
| 14832 } |
| 14833 return { |
| 14834 name: pieces[0], |
| 14835 direction: pieces[1], |
| 14836 } |
| 14837 }, |
| 14838 |
| 14839 _sortChange: function(e) { |
| 14840 // The event we get from sort-toggle tells us the name of what needs |
| 14841 // to be sorting and how to sort it. |
| 14842 if (!(e && e.detail && e.detail.name)) { |
| 14843 return; |
| 14844 } |
| 14845 // should trigger the computation of _sort and __filterAndSort |
| 14846 this.set("_sortstr", e.detail.name +":"+e.detail.direction); |
| 14847 }, |
| 14848 // _stripSpecial removes the special columns and sorts the remaining |
| 14849 // columns so they always appear in the same order, regardless of |
| 14850 // the order they are added. |
| 14851 _stripSpecial: function(){ |
| 14852 return this._columns.filter(function(c){ |
| 14853 return this._specialColumns.indexOf(c) === -1; |
| 14854 }.bind(this)).sort(); |
| 14855 }, |
| 14856 |
| 14857 }; |
| 14858 })(); |
| 14859 </script> |
| 14860 |
| 14861 <script> |
| 14681 | 14862 |
| 14682 (function() { | 14863 (function() { |
| 14683 | 14864 |
| 14684 // monostate data | 14865 // monostate data |
| 14685 var metaDatas = {}; | 14866 var metaDatas = {}; |
| 14686 var metaArrays = {}; | 14867 var metaArrays = {}; |
| 14687 var singleton = null; | 14868 var singleton = null; |
| 14688 | 14869 |
| 14689 Polymer.IronMeta = Polymer({ | 14870 Polymer.IronMeta = Polymer({ |
| 14690 | 14871 |
| (...skipping 7987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 22678 Polymer({ | 22859 Polymer({ |
| 22679 is: 'paper-input', | 22860 is: 'paper-input', |
| 22680 | 22861 |
| 22681 behaviors: [ | 22862 behaviors: [ |
| 22682 Polymer.IronFormElementBehavior, | 22863 Polymer.IronFormElementBehavior, |
| 22683 Polymer.PaperInputBehavior | 22864 Polymer.PaperInputBehavior |
| 22684 ] | 22865 ] |
| 22685 }); | 22866 }); |
| 22686 </script> | 22867 </script> |
| 22687 <script> | 22868 <script> |
| 22688 | |
| 22689 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; | |
| 22690 (function(){ | 22869 (function(){ |
| 22691 var ANDROID_ALIASES = { | 22870 var ANDROID_ALIASES = { |
| 22692 "bullhead": "Nexus 5X", | 22871 "bullhead": "Nexus 5X", |
| 22693 "flo": "Nexus 7 (2013)", | 22872 "flo": "Nexus 7 (2013)", |
| 22694 "flounder": "Nexus 9", | 22873 "flounder": "Nexus 9", |
| 22695 "foster": "NVIDIA Shield", | 22874 "foster": "NVIDIA Shield", |
| 22696 "fugu": "Nexus Player", | 22875 "fugu": "Nexus Player", |
| 22697 "grouper": "Nexus 7 (2012)", | 22876 "grouper": "Nexus 7 (2012)", |
| 22698 "hammerhead": "Nexus 5", | 22877 "hammerhead": "Nexus 5", |
| 22699 "m0": "Galaxy S3", | 22878 "m0": "Galaxy S3", |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 22735 "8086:0a2e": "Intel Haswell Integrated", | 22914 "8086:0a2e": "Intel Haswell Integrated", |
| 22736 "8086:0d26": "Intel Crystal Well Integrated", | 22915 "8086:0d26": "Intel Crystal Well Integrated", |
| 22737 "8086:22b1": "Intel Braswell Integrated", | 22916 "8086:22b1": "Intel Braswell Integrated", |
| 22738 } | 22917 } |
| 22739 | 22918 |
| 22740 // For consistency, all aliases are displayed like: | 22919 // For consistency, all aliases are displayed like: |
| 22741 // Nexus 5X (bullhead) | 22920 // Nexus 5X (bullhead) |
| 22742 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. | 22921 // This regex matches a string like "ALIAS (ORIG)", with ORIG as group 1. |
| 22743 var ALIAS_REGEXP = /.+ \((.*)\)/; | 22922 var ALIAS_REGEXP = /.+ \((.*)\)/; |
| 22744 | 22923 |
| 22745 // This behavior wraps up all the shared bot-list functionality. | 22924 // This behavior wraps up all the shared bot-list functionality by |
| 22746 SwarmingBehaviors.BotListBehavior = { | 22925 // extending SwarmingBehaviors.SwarmingBehavior |
| 22926 SwarmingBehaviors.BotListBehavior = [SwarmingBehaviors.SwarmingBehavior, { |
| 22747 | 22927 |
| 22748 properties: { | 22928 properties: { |
| 22749 DIMENSIONS_WITH_ALIASES: { | 22929 DIMENSIONS_WITH_ALIASES: { |
| 22750 type: Array, | 22930 type: Array, |
| 22751 value: function(){ | 22931 value: function(){ |
| 22752 return ["device_type", "gpu"]; | 22932 return ["device_type", "gpu"]; |
| 22753 }, | 22933 }, |
| 22754 }, | 22934 }, |
| 22755 BOT_PROPERTIES: { | 22935 BOT_PROPERTIES: { |
| 22756 type: Array, | 22936 type: Array, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 22811 return bot.dimensions[i].value; | 22991 return bot.dimensions[i].value; |
| 22812 } | 22992 } |
| 22813 } | 22993 } |
| 22814 return undefined; | 22994 return undefined; |
| 22815 }, | 22995 }, |
| 22816 | 22996 |
| 22817 _gpuAlias: function(gpu) { | 22997 _gpuAlias: function(gpu) { |
| 22818 return GPU_ALIASES[gpu] || UNKNOWN; | 22998 return GPU_ALIASES[gpu] || UNKNOWN; |
| 22819 }, | 22999 }, |
| 22820 | 23000 |
| 22821 _not: function(a) { | |
| 22822 return !a; | |
| 22823 }, | |
| 22824 | |
| 22825 _or: function() { | |
| 22826 var result = false; | |
| 22827 // can't use .foreach, as arguments isn't really a function. | |
| 22828 for (var i = 0; i < arguments.length; i++) { | |
| 22829 result = result || arguments[i]; | |
| 22830 } | |
| 22831 return result; | |
| 22832 }, | |
| 22833 | |
| 22834 // _state returns the requested attribute from a bot's state. | 23001 // _state returns the requested attribute from a bot's state. |
| 22835 // For consistency with _dimension, if the attribute is not an array, | 23002 // For consistency with _dimension, if the attribute is not an array, |
| 22836 // it is put as the only element in an array. | 23003 // it is put as the only element in an array. |
| 22837 _state: function(bot, attr) { | 23004 _state: function(bot, attr) { |
| 22838 if (!bot || !bot.state || !bot.state[attr]) { | 23005 if (!bot || !bot.state || !bot.state[attr]) { |
| 22839 return undefined | 23006 return undefined |
| 22840 } | 23007 } |
| 22841 var state = bot.state[attr]; | 23008 var state = bot.state[attr]; |
| 22842 if (Array.isArray(state)) { | 23009 if (Array.isArray(state)) { |
| 22843 return state; | 23010 return state; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 22854 | 23021 |
| 22855 // _unalias will return the base dimension/state with its alias removed | 23022 // _unalias will return the base dimension/state with its alias removed |
| 22856 // if it had one. This is handy for sorting and filtering. | 23023 // if it had one. This is handy for sorting and filtering. |
| 22857 _unalias: function(str) { | 23024 _unalias: function(str) { |
| 22858 var match = ALIAS_REGEXP.exec(str); | 23025 var match = ALIAS_REGEXP.exec(str); |
| 22859 if (match) { | 23026 if (match) { |
| 22860 return match[1]; | 23027 return match[1]; |
| 22861 } | 23028 } |
| 22862 return str; | 23029 return str; |
| 22863 }, | 23030 }, |
| 22864 } | 23031 }]; |
| 22865 })() | 23032 })() |
| 22866 </script> | 23033 </script> |
| 22867 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> | 23034 <dom-module id="bot-filters" assetpath="/res/imp/botlist/"> |
| 22868 <template> | 23035 <template> |
| 22869 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning"> | 23036 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning"> |
| 22870 :host { | 23037 :host { |
| 22871 display: block; | 23038 display: block; |
| 22872 font-family: sans-serif; | 23039 font-family: sans-serif; |
| 22873 } | 23040 } |
| 22874 #filter { | 23041 #filter { |
| (...skipping 924 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 23799 curr.alive++; | 23966 curr.alive++; |
| 23800 } | 23967 } |
| 23801 curr.all++; | 23968 curr.all++; |
| 23802 }.bind(this)); | 23969 }.bind(this)); |
| 23803 this.set("_currently_showing", curr); | 23970 this.set("_currently_showing", curr); |
| 23804 } | 23971 } |
| 23805 }); | 23972 }); |
| 23806 </script> | 23973 </script> |
| 23807 </dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/"> | 23974 </dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/"> |
| 23808 <template> | 23975 <template> |
| 23809 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-
style"> | 23976 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-
style dynamic-table-style"> |
| 23810 bot-filters, bot-list-summary { | 23977 bot-filters, bot-list-summary { |
| 23811 margin-bottom: 8px; | 23978 margin-bottom: 8px; |
| 23812 margin-right: 10px; | 23979 margin-right: 10px; |
| 23813 } | 23980 } |
| 23814 .bot { | |
| 23815 margin:5px; | |
| 23816 max-width:400px; | |
| 23817 min-height:100px; | |
| 23818 min-width:300px; | |
| 23819 } | |
| 23820 table { | |
| 23821 border-collapse: collapse; | |
| 23822 margin-left: 5px; | |
| 23823 } | |
| 23824 td, th { | |
| 23825 border: 1px solid #DDD; | |
| 23826 padding: 5px; | |
| 23827 } | |
| 23828 | |
| 23829 .quarantined, .bad-device { | 23981 .quarantined, .bad-device { |
| 23830 background-color: #ffdddd; | 23982 background-color: #ffdddd; |
| 23831 } | 23983 } |
| 23832 .dead { | 23984 .dead { |
| 23833 background-color: #cccccc; | 23985 background-color: #cccccc; |
| 23834 } | 23986 } |
| 23835 | |
| 23836 th { | |
| 23837 position: relative; | |
| 23838 } | |
| 23839 sort-toggle { | |
| 23840 position: absolute; | |
| 23841 right: 0; | |
| 23842 top: 0.4em; | |
| 23843 } | |
| 23844 .bot-list th > span { | 23987 .bot-list th > span { |
| 23845 /* Leave space for sort-toggle*/ | 23988 /* Leave space for sort-toggle*/ |
| 23846 padding-right: 30px; | 23989 padding-right: 30px; |
| 23847 } | 23990 } |
| 23848 </style> | 23991 </style> |
| 23849 | 23992 |
| 23850 <url-param name="sort" value="{{_sortstr}}" default_value="id:asc"> | 23993 <url-param name="sort" value="{{_sortstr}}" default_value="id:asc"> |
| 23851 </url-param> | 23994 </url-param> |
| 23852 | 23995 |
| 23853 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" sig
ned_in="{{_signed_in}}" busy="[[_busy]]" name="Swarming Bot List"> | 23996 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" sig
ned_in="{{_signed_in}}" busy="[[_busy]]" name="Swarming Bot List"> |
| 23854 | 23997 |
| 23855 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> | 23998 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> |
| 23856 | 23999 |
| 23857 <div hidden$="[[_not(_signed_in)]]"> | 24000 <div hidden$="[[_not(_signed_in)]]"> |
| 23858 | 24001 |
| 23859 <div class="horizontal layout"> | 24002 <div class="horizontal layout"> |
| 23860 | 24003 |
| 23861 <bot-filters dimensions="[[_dimensions]]" primary_map="[[_primary_map]
]" primary_arr="[[_primary_arr]]" columns="{{_columns}}" query_params="{{_query_
params}}" filter="{{_filter}}" verbose="{{_verbose}}"> | 24004 <bot-filters dimensions="[[_dimensions]]" primary_map="[[_primary_map]
]" primary_arr="[[_primary_arr]]" columns="{{_columns}}" query_params="{{_query_
params}}" filter="{{_filter}}" verbose="{{_verbose}}"> |
| 23862 </bot-filters> | 24005 </bot-filters> |
| 23863 | 24006 |
| 23864 <bot-list-summary columns="[[_columns]]" fleet="[[_fleet]]" filtered_b
ots="[[_filteredSortedBots]]" sort="[[_sortstr]]" verbose="[[_verbose]]"> | 24007 <bot-list-summary columns="[[_columns]]" fleet="[[_fleet]]" filtered_b
ots="[[_filteredSortedItems]]" sort="[[_sortstr]]" verbose="[[_verbose]]"> |
| 23865 </bot-list-summary> | 24008 </bot-list-summary> |
| 23866 | 24009 |
| 23867 </div> | 24010 </div> |
| 23868 | 24011 |
| 23869 <bot-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_p
arams]]" bots="{{_bots}}" busy="{{_busy}}" dimensions="{{_dimensions}}" fleet="{
{_fleet}}" primary_map="{{_primary_map}}" primary_arr="{{_primary_arr}}"> | 24012 <bot-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_p
arams]]" bots="{{_items}}" busy="{{_busy}}" dimensions="{{_dimensions}}" fleet="
{{_fleet}}" primary_map="{{_primary_map}}" primary_arr="{{_primary_arr}}"> |
| 23870 </bot-list-data> | 24013 </bot-list-data> |
| 23871 | 24014 |
| 23872 <table class="bot-list"> | 24015 <table class="bot-list"> |
| 23873 <thead on-sort_change="_sortChange"> | 24016 <thead on-sort_change="_sortChange"> |
| 23874 | 24017 |
| 23875 <tr> | 24018 <tr> |
| 23876 <th> | 24019 <th> |
| 23877 <span>Bot Id</span> | 24020 <span>Bot Id</span> |
| 23878 <sort-toggle name="id" current="[[_sort]]"> | 24021 <sort-toggle name="id" current="[[_sort]]"> |
| 23879 </sort-toggle> | 24022 </sort-toggle> |
| 23880 </th> | 24023 </th> |
| 23881 | 24024 |
| 23882 <th hidden$="[[_hide('task', _columns.*)]]"> | 24025 <th hidden$="[[_hide('task', _columns.*)]]"> |
| 23883 <span>Current Task</span> | 24026 <span>Current Task</span> |
| 23884 <sort-toggle name="task" current="[[_sort]]"> | 24027 <sort-toggle name="task" current="[[_sort]]"> |
| 23885 </sort-toggle> | 24028 </sort-toggle> |
| 23886 </th> | 24029 </th> |
| 23887 | 24030 |
| 23888 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> | 24031 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> |
| 23889 <th hidden$="[[_hide(c)]]"> | 24032 <th hidden$="[[_hide(c)]]"> |
| 23890 <span>[[_header(c)]]</span> | 24033 <span>[[_header(c)]]</span> |
| 23891 <sort-toggle name="[[c]]" current="[[_sort]]"> | 24034 <sort-toggle name="[[c]]" current="[[_sort]]"> |
| 23892 </sort-toggle> | 24035 </sort-toggle> |
| 23893 </th> | 24036 </th> |
| 23894 </template> | 24037 </template> |
| 23895 </tr> | 24038 </tr> |
| 23896 </thead> | 24039 </thead> |
| 23897 <tbody> | 24040 <tbody> |
| 23898 <template id="bot_table" is="dom-repeat" items="[[_filteredSortedBot
s]]" as="bot" initial-count="50"> | 24041 <template id="bot_table" is="dom-repeat" items="[[_filteredSortedIte
ms]]" as="bot" initial-count="50"> |
| 23899 | 24042 |
| 23900 <tr class$="[[_botClass(bot)]]"> | 24043 <tr class$="[[_botClass(bot)]]"> |
| 23901 <td> | 24044 <td> |
| 23902 <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_bl
ank"> | 24045 <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_bl
ank"> |
| 23903 [[bot.bot_id]] | 24046 [[bot.bot_id]] |
| 23904 </a> | 24047 </a> |
| 23905 </td> | 24048 </td> |
| 23906 <td hidden$="[[_hide('task', _columns.*)]]"> | 24049 <td hidden$="[[_hide('task', _columns.*)]]"> |
| 23907 <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a> | 24050 <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a> |
| 23908 </td> | 24051 </td> |
| 23909 | 24052 |
| 23910 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> | 24053 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> |
| 23911 <td hidden$="[[_hide(c)]]"> | 24054 <td hidden$="[[_hide(c)]]"> |
| 23912 [[_column(c, bot, _verbose)]] | 24055 [[_column(c, bot, _verbose)]] |
| 23913 </td> | 24056 </td> |
| 23914 </template> | 24057 </template> |
| 23915 | 24058 |
| 23916 </tr> | 24059 </tr> |
| 23917 <template is="dom-repeat" items="[[_devices(bot)]]" as="device"> | 24060 <template is="dom-repeat" items="[[_devices(bot)]]" as="device"> |
| 23918 <tr hidden$="[[_hide('android_devices', _columns.*)]]" class$="[
[_deviceClass(device)]]"> | 24061 <tr hidden$="[[_hide('android_devices', _columns.*)]]" class$="[
[_deviceClass(device)]]"> |
| 23919 <td></td> | 24062 <td></td> |
| 23920 <td hidden$="[[_hide('task', _columns.*)]]"></td> | 24063 <td hidden$="[[_hide('task', _columns.*)]]"></td> |
| 23921 <template is="dom-repeat" items="[[_plain_columns]]" as="c"> | 24064 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> |
| 23922 <td hidden$="[[_hide(c)]]"> | 24065 <td hidden$="[[_hide(c)]]"> |
| 23923 [[_deviceColumn(c, device, _verbose)]] | 24066 [[_deviceColumn(c, device, _verbose)]] |
| 23924 </td> | 24067 </td> |
| 23925 </template> | 24068 </template> |
| 23926 </tr> | 24069 </tr> |
| 23927 </template> | 24070 </template> |
| 23928 </template> | 24071 </template> |
| 23929 </tbody> | 24072 </tbody> |
| 23930 </table> | 24073 </table> |
| 23931 </div> | 24074 </div> |
| 23932 | 24075 |
| 23933 </swarming-app> | 24076 </swarming-app> |
| 23934 | 24077 |
| 23935 </template> | 24078 </template> |
| 23936 <script> | 24079 <script> |
| 23937 (function(){ | 24080 (function(){ |
| 23938 var special_columns = ["id", "task"]; | 24081 // see dynamic-table for more information on specialColumns, headerMap, |
| 24082 // columnMap, and specialSort |
| 24083 var specialColumns = ["id", "task"]; |
| 23939 | 24084 |
| 23940 var headerMap = { | 24085 var headerMap = { |
| 23941 // "id" and "task" are special, so they don't go here and have their | 24086 // "id" and "task" are special, so they don't go here. They have their |
| 23942 // headers hard-coded below. | 24087 // headers hard-coded above. |
| 23943 "android_devices": "Android Devices", | 24088 "android_devices": "Android Devices", |
| 23944 "cores": "Cores", | 24089 "cores": "Cores", |
| 23945 "cpu": "CPU", | 24090 "cpu": "CPU", |
| 23946 "device": "Non-android Device", | 24091 "device": "Non-android Device", |
| 23947 "device_os": "Device OS", | 24092 "device_os": "Device OS", |
| 23948 "device_type": "Device Type", | 24093 "device_type": "Device Type", |
| 23949 "disk_space": "Free Space (MB)", | 24094 "disk_space": "Free Space (MB)", |
| 23950 "gpu": "GPU", | 24095 "gpu": "GPU", |
| 23951 "os": "OS", | 24096 "os": "OS", |
| 23952 "pool": "Pool", | 24097 "pool": "Pool", |
| 23953 "status": "Status", | 24098 "status": "Status", |
| 23954 "xcode_version": "XCode Version", | 24099 "xcode_version": "XCode Version", |
| 23955 }; | 24100 }; |
| 23956 | 24101 |
| 23957 // This maps column name to a function that will return the content for a | |
| 23958 // given bot. These functions are bound to this element, and have access | |
| 23959 // to all functions defined here and in bot-list-shared. If a column | |
| 23960 // is not listed here, a sane default will be used (see _column()). | |
| 23961 var columnMap = { | 24102 var columnMap = { |
| 23962 android_devices: function(bot) { | 24103 android_devices: function(bot) { |
| 23963 var devs = this._attribute(bot, "android_devices", "0"); | 24104 var devs = this._attribute(bot, "android_devices", "0"); |
| 23964 if (this._verbose) { | 24105 if (this._verbose) { |
| 23965 return devs.join(" | ") + " devices available"; | 24106 return devs.join(" | ") + " devices available"; |
| 23966 } | 24107 } |
| 23967 // max() works on strings as long as they can be coerced to Number. | 24108 // max() works on strings as long as they can be coerced to Number. |
| 23968 return Math.max(...devs) + " devices available"; | 24109 return Math.max(...devs) + " devices available"; |
| 23969 }, | 24110 }, |
| 23970 device_type: function(bot) { | 24111 device_type: function(bot) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 24050 if (device.build) { | 24191 if (device.build) { |
| 24051 return device.build["build.id"]; | 24192 return device.build["build.id"]; |
| 24052 } | 24193 } |
| 24053 return "unknown"; | 24194 return "unknown"; |
| 24054 }, | 24195 }, |
| 24055 status: function(device) { | 24196 status: function(device) { |
| 24056 return device.state; | 24197 return device.state; |
| 24057 } | 24198 } |
| 24058 } | 24199 } |
| 24059 | 24200 |
| 24060 // specialSort defines any custom sorting rules. By default, a | |
| 24061 // naturalCompare of the column content is done. | |
| 24062 var specialSort = { | 24201 var specialSort = { |
| 24063 android_devices: function(dir, botA, botB) { | 24202 android_devices: function(dir, botA, botB) { |
| 24064 // We sort on the number of attached devices. Note that this | 24203 // We sort on the number of attached devices. Note that this |
| 24065 // may not be the same as android_devices, because _devices().length | 24204 // may not be the same as android_devices, because _devices().length |
| 24066 // counts all devices plugged into the bot, whereas android_devices | 24205 // counts all devices plugged into the bot, whereas android_devices |
| 24067 // counts just devices ready for work. | 24206 // counts just devices ready for work. |
| 24068 var botACol = this._devices(botA).length; | 24207 var botACol = this._devices(botA).length; |
| 24069 var botBCol = this._devices(botB).length; | 24208 var botBCol = this._devices(botB).length; |
| 24070 return dir * swarming.naturalCompare(botACol, botBCol); | 24209 return dir * swarming.naturalCompare(botACol, botBCol); |
| 24071 }, | 24210 }, |
| 24072 disk_space: function(dir, botA, botB) { | 24211 disk_space: function(dir, botA, botB) { |
| 24073 // We sort based on the raw number of MB of the first disk. | 24212 // We sort based on the raw number of MB of the first disk. |
| 24074 var botACol = botA.disks[0].mb; | 24213 var botACol = botA.disks[0].mb; |
| 24075 var botBCol = botB.disks[0].mb;; | 24214 var botBCol = botB.disks[0].mb;; |
| 24076 return dir * swarming.naturalCompare(botACol, botBCol); | 24215 return dir * swarming.naturalCompare(botACol, botBCol); |
| 24077 }, | 24216 }, |
| 24078 }; | 24217 }; |
| 24079 | 24218 |
| 24080 Polymer({ | 24219 Polymer({ |
| 24081 is: 'bot-list', | 24220 is: 'bot-list', |
| 24082 behaviors: [SwarmingBehaviors.BotListBehavior], | 24221 behaviors: [SwarmingBehaviors.BotListBehavior, |
| 24222 SwarmingBehaviors.DynamicTableBehavior], |
| 24083 | 24223 |
| 24084 properties: { | 24224 properties: { |
| 24085 | 24225 |
| 24086 client_id: { | 24226 client_id: { |
| 24087 type: String, | 24227 type: String, |
| 24088 }, | 24228 }, |
| 24089 | 24229 |
| 24090 _bots: { | 24230 // for dynamic table |
| 24231 _columnMap: { |
| 24232 type: Object, |
| 24233 value: function() { |
| 24234 return columnMap; |
| 24235 } |
| 24236 }, |
| 24237 _headerMap: { |
| 24238 type: Object, |
| 24239 value: function() { |
| 24240 return headerMap; |
| 24241 }, |
| 24242 }, |
| 24243 // special columns contain html. non-special (i.e. normal colunns) just |
| 24244 // contain text. |
| 24245 _specialColumns: { |
| 24091 type: Array, | 24246 type: Array, |
| 24247 value: function() { |
| 24248 return specialColumns; |
| 24249 } |
| 24250 }, |
| 24251 _specialSort: { |
| 24252 type: Object, |
| 24253 value: function() { |
| 24254 return specialSort; |
| 24255 } |
| 24092 }, | 24256 }, |
| 24093 | 24257 |
| 24094 _columns: { | |
| 24095 type: Array, | |
| 24096 }, | |
| 24097 | |
| 24098 _filter: { | |
| 24099 type: Function, | |
| 24100 value: function() { | |
| 24101 return true; | |
| 24102 }, | |
| 24103 }, | |
| 24104 | |
| 24105 _filteredSortedBots: { | |
| 24106 type: Array, | |
| 24107 computed: "_filterAndSort(_bots,_filter.*,_sort.*)" | |
| 24108 }, | |
| 24109 | |
| 24110 _plain_columns: { | |
| 24111 type: Array, | |
| 24112 computed: "_stripSpecial(_columns.*)", | |
| 24113 }, | |
| 24114 | |
| 24115 // _sort is an Object {name:String, direction:String}. | |
| 24116 _sort: { | |
| 24117 type: Object, | |
| 24118 computed: "_makeObject(_sortstr)", | |
| 24119 }, | |
| 24120 | |
| 24121 _verbose: { | |
| 24122 type: Boolean, | |
| 24123 } | |
| 24124 }, | 24258 }, |
| 24125 | 24259 |
| 24126 _botClass: function(bot) { | 24260 _botClass: function(bot) { |
| 24127 if (bot.is_dead) { | 24261 if (bot.is_dead) { |
| 24128 return "dead"; | 24262 return "dead"; |
| 24129 } | 24263 } |
| 24130 if (bot.quarantined) { | 24264 if (bot.quarantined) { |
| 24131 return "quarantined"; | 24265 return "quarantined"; |
| 24132 } | 24266 } |
| 24133 return ""; | 24267 return ""; |
| 24134 }, | 24268 }, |
| 24135 | 24269 |
| 24136 _botLink: function(id) { | 24270 _botLink: function(id) { |
| 24137 // TODO(kjlubick) Make this point to /newui/ when appropriate. | 24271 // TODO(kjlubick) Make this point to /newui/ when appropriate. |
| 24138 return "/restricted/bot/"+id; | 24272 return "/restricted/bot/"+id; |
| 24139 }, | 24273 }, |
| 24140 | 24274 |
| 24141 | 24275 |
| 24142 _column: function(col, bot) { | |
| 24143 var f = columnMap[col]; | |
| 24144 if (!f) { | |
| 24145 f = function(bot) { | |
| 24146 var c = this._attribute(bot, col, "none"); | |
| 24147 if (this._verbose) { | |
| 24148 return c.join(" | "); | |
| 24149 } | |
| 24150 return c[0]; | |
| 24151 } | |
| 24152 } | |
| 24153 return f.bind(this)(bot); | |
| 24154 }, | |
| 24155 | |
| 24156 _androidAliasDevice: function(device) { | 24276 _androidAliasDevice: function(device) { |
| 24157 if (device.notReady) { | 24277 if (device.notReady) { |
| 24158 return UNAUTHENTICATED.toUpperCase(); | 24278 return UNAUTHENTICATED.toUpperCase(); |
| 24159 } | 24279 } |
| 24160 return this._androidAlias(this._deviceType(device)); | 24280 return this._androidAlias(this._deviceType(device)); |
| 24161 }, | 24281 }, |
| 24162 | 24282 |
| 24163 _deviceColumn: function(col, device) { | 24283 _deviceColumn: function(col, device) { |
| 24164 var f = deviceColumnMap[col]; | 24284 var f = deviceColumnMap[col]; |
| 24165 if (!f || !device) { | 24285 if (!f || !device) { |
| 24166 return ""; | 24286 return ""; |
| 24167 } | 24287 } |
| 24168 return f.bind(this)(device); | 24288 return f.bind(this)(device); |
| 24169 }, | 24289 }, |
| 24170 | 24290 |
| 24171 _deviceClass: function(device) { | 24291 _deviceClass: function(device) { |
| 24172 if (!device.okay) { | 24292 if (!device.okay) { |
| 24173 return "bad-device"; | 24293 return "bad-device"; |
| 24174 } | 24294 } |
| 24175 return ""; | 24295 return ""; |
| 24176 }, | 24296 }, |
| 24177 | 24297 |
| 24178 _filterAndSort: function(a,b,c) { | |
| 24179 // We intentionally sort this._bots (and not a copy) to allow users to | |
| 24180 // "chain" sorts, that is, sort by one thing and then another, and | |
| 24181 // have both orderings properly impact the list. | |
| 24182 swarming.stableSort(this._bots, this._sortBotTable.bind(this)); | |
| 24183 var bots = this._bots; | |
| 24184 if (this._filter) { | |
| 24185 bots = bots.filter(this._filter.bind(this)); | |
| 24186 } | |
| 24187 | |
| 24188 return bots; | |
| 24189 }, | |
| 24190 | |
| 24191 _header: function(col){ | |
| 24192 return headerMap[col] || col; | |
| 24193 }, | |
| 24194 | |
| 24195 _hide: function(col) { | |
| 24196 return this._columns.indexOf(col) === -1; | |
| 24197 }, | |
| 24198 | |
| 24199 _makeObject: function(sortstr){ | |
| 24200 if (!sortstr) { | |
| 24201 return undefined; | |
| 24202 } | |
| 24203 var pieces = sortstr.split(":"); | |
| 24204 if (pieces.length != 2) { | |
| 24205 // fail safe | |
| 24206 return {name: "id", direction:"desc"}; | |
| 24207 } | |
| 24208 return { | |
| 24209 name: pieces[0], | |
| 24210 direction: pieces[1], | |
| 24211 } | |
| 24212 }, | |
| 24213 | |
| 24214 _reRender: function(filter, sort) { | |
| 24215 this.$.bot_table.render(); | |
| 24216 }, | |
| 24217 | |
| 24218 _sortBotTable: function(botA, botB) { | |
| 24219 if (!this._sort) { | |
| 24220 return 0; | |
| 24221 } | |
| 24222 var dir = 1; | |
| 24223 if (this._sort.direction === "desc") { | |
| 24224 dir = -1; | |
| 24225 } | |
| 24226 var sort = specialSort[this._sort.name]; | |
| 24227 if (sort) { | |
| 24228 return sort.bind(this)(dir, botA, botB); | |
| 24229 } | |
| 24230 // Default to a natural compare of the columns. | |
| 24231 var botACol = this._column(this._sort.name, botA); | |
| 24232 var botBCol = this._column(this._sort.name, botB); | |
| 24233 | |
| 24234 return dir * swarming.naturalCompare(botACol, botBCol); | |
| 24235 }, | |
| 24236 | |
| 24237 _sortChange: function(e) { | |
| 24238 // The event we get from sort-toggle tells us the name of what needs | |
| 24239 // to be sorting and how to sort it. | |
| 24240 if (!(e && e.detail && e.detail.name)) { | |
| 24241 return; | |
| 24242 } | |
| 24243 // should trigger the computation of _sort and __filterAndSort | |
| 24244 this.set("_sortstr", e.detail.name +":"+e.detail.direction); | |
| 24245 }, | |
| 24246 | |
| 24247 // _stripSpecial removes the special columns and sorts the remaining | |
| 24248 // columns so they always appear in the same order, regardless of | |
| 24249 // the order they are added. | |
| 24250 _stripSpecial: function(){ | |
| 24251 return this._columns.filter(function(c){ | |
| 24252 return special_columns.indexOf(c) === -1; | |
| 24253 }).sort(); | |
| 24254 }, | |
| 24255 | |
| 24256 _taskLink: function(data) { | 24298 _taskLink: function(data) { |
| 24257 if (data && data.task_id) { | 24299 if (data && data.task_id) { |
| 24258 return "/user/task/" + data.task_id; | 24300 return "/user/task/" + data.task_id; |
| 24259 } | 24301 } |
| 24260 return undefined; | 24302 return undefined; |
| 24261 } | 24303 } |
| 24262 | 24304 |
| 24263 }); | 24305 }); |
| 24264 })(); | 24306 })(); |
| 24265 </script> | 24307 </script> |
| 24266 </dom-module></div></body></html> | 24308 </dom-module></div></body></html> |
| OLD | NEW |