Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: appengine/swarming/elements/build/elements.html

Issue 2204483002: Add UI to new botlist to show summary (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@bot-summary-api
Patch Set: add docs Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 14478 matching lines...) Expand 10 before | Expand all | Expand 10 after
14489 clientId: { 14489 clientId: {
14490 type: String, 14490 type: String,
14491 }, 14491 },
14492 profile: { 14492 profile: {
14493 type: Object, 14493 type: Object,
14494 readOnly: true 14494 readOnly: true
14495 }, 14495 },
14496 signedIn: { 14496 signedIn: {
14497 type: Boolean, 14497 type: Boolean,
14498 readOnly: true, 14498 readOnly: true,
14499 value: false 14499 value: false,
14500 notify: true,
14500 } 14501 }
14501 }, 14502 },
14502 14503
14503 _onSignin: function(e) { 14504 _onSignin: function(e) {
14504 this._setSignedIn(true); 14505 this._setSignedIn(true);
14505 var user = gapi.auth2.getAuthInstance().currentUser.get(); 14506 var user = gapi.auth2.getAuthInstance().currentUser.get();
14506 var profile = user.getBasicProfile(); 14507 var profile = user.getBasicProfile();
14507 this._setProfile({ 14508 this._setProfile({
14508 email: profile.getEmail(), 14509 email: profile.getEmail(),
14509 imageUrl: profile.getImageUrl() 14510 imageUrl: profile.getImageUrl()
14510 }); 14511 });
14511 this.set("authResponse", user.getAuthResponse()); 14512 this.set("authResponse", user.getAuthResponse());
14513 this._setSignedIn(true);
14512 this.fire("auth-signin"); 14514 this.fire("auth-signin");
14513 }, 14515 },
14514 14516
14515 _onSignout: function(e) { 14517 _onSignout: function(e) {
14516 this._setSignedIn(false); 14518 this._setSignedIn(false);
14517 this._setProfile(null); 14519 this._setProfile(null);
14518 }, 14520 },
14519 14521
14520 _makeHeader: function(authResponse) { 14522 _makeHeader: function(authResponse) {
14521 if (!authResponse) { 14523 if (!authResponse) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
14575 <app-header-layout> 14577 <app-header-layout>
14576 <app-header fixed=""> 14578 <app-header fixed="">
14577 <app-toolbar> 14579 <app-toolbar>
14578 <div class="title left">[[name]]</div> 14580 <div class="title left">[[name]]</div>
14579 <paper-spinner-lite class="left" active="[[busy]]"></paper-spinner-lit e> 14581 <paper-spinner-lite class="left" active="[[busy]]"></paper-spinner-lit e>
14580 14582
14581 <a class="left" href="/newui/">Home</a> 14583 <a class="left" href="/newui/">Home</a>
14582 <a class="left" href="/newui/botlist">Bot List</a> 14584 <a class="left" href="/newui/botlist">Bot List</a>
14583 <div class="flex"></div> 14585 <div class="flex"></div>
14584 14586
14585 <auth-signin class="right" client-id="20770472288-t5smpbpjptka4nd888fv 0ctd23ftba2o.apps.googleusercontent.com" auth-headers="{{auth_headers}}"> 14587 <auth-signin class="right" client-id="20770472288-t5smpbpjptka4nd888fv 0ctd23ftba2o.apps.googleusercontent.com" auth-headers="{{auth_headers}}" signed- in="{{signed_in}}">
14586 </auth-signin> 14588 </auth-signin>
14587 </app-toolbar> 14589 </app-toolbar>
14588 </app-header> 14590 </app-header>
14589 <div class="main-content"> 14591 <div class="main-content">
14590 <content></content> 14592 <content></content>
14591 </div> 14593 </div>
14592 </app-header-layout> 14594 </app-header-layout>
14593 14595
14594 </template> 14596 </template>
14595 <script> 14597 <script>
14596 Polymer({ 14598 Polymer({
14597 is: 'swarming-app', 14599 is: 'swarming-app',
14598 properties: { 14600 properties: {
14599 auth_headers: { 14601 auth_headers: {
14600 type: Object, 14602 type: Object,
14601 notify: true, 14603 notify: true,
14602 }, 14604 },
14605 signed_in: {
14606 type: Boolean,
14607 value: false,
14608 notify:true,
14609 },
14610
14603 busy: { 14611 busy: {
14604 type: Boolean, 14612 type: Boolean,
14605 }, 14613 },
14606 name: { 14614 name: {
14607 type: String, 14615 type: String,
14608 }, 14616 },
14609 }, 14617 },
14610 14618
14611 }); 14619 });
14612 </script> 14620 </script>
(...skipping 962 matching lines...) Expand 10 before | Expand all | Expand 10 after
15575 <iron-icon style="top:0" class$="[[_hidden(direction,'asc')]]" icon="icons :arrow-drop-down"> 15583 <iron-icon style="top:0" class$="[[_hidden(direction,'asc')]]" icon="icons :arrow-drop-down">
15576 </iron-icon> 15584 </iron-icon>
15577 <iron-icon style="bottom:0" class$="[[_hidden(direction,'desc')]]" icon="i cons:arrow-drop-up"> 15585 <iron-icon style="bottom:0" class$="[[_hidden(direction,'desc')]]" icon="i cons:arrow-drop-up">
15578 </iron-icon> 15586 </iron-icon>
15579 </span> 15587 </span>
15580 15588
15581 </template> 15589 </template>
15582 <script> 15590 <script>
15583 Polymer({ 15591 Polymer({
15584 is: "sort-toggle", 15592 is: "sort-toggle",
15593
15585 properties: { 15594 properties: {
15586 current: { 15595 current: {
15587 type: Object, 15596 type: Object,
15588 observer: "_resetSort", 15597 observer: "_resetSort",
15589 }, 15598 },
15590 name: { 15599 name: {
15591 type: String, 15600 type: String,
15592 observer: "_resetSort", 15601 observer: "_resetSort",
15593 }, 15602 },
15594 15603
(...skipping 24 matching lines...) Expand all
15619 // Because of how Polymer inserts and moves elements around, we need to 15628 // Because of how Polymer inserts and moves elements around, we need to
15620 // update the direction value if the name changes so the ascending sort 15629 // update the direction value if the name changes so the ascending sort
15621 // by "os" doesn't become the ascending sort by "gpu" if a column gets 15630 // by "os" doesn't become the ascending sort by "gpu" if a column gets
15622 // added before "os", for example. Additionally, this makes sure that 15631 // added before "os", for example. Additionally, this makes sure that
15623 // only one sort-toggle is active at a given time. 15632 // only one sort-toggle is active at a given time.
15624 if (this.current && this.current.name === this.name) { 15633 if (this.current && this.current.name === this.name) {
15625 this.set("direction", this.current.direction); 15634 this.set("direction", this.current.direction);
15626 } else { 15635 } else {
15627 this.set("direction", ""); 15636 this.set("direction", "");
15628 } 15637 }
15629
15630 }, 15638 },
15631 }); 15639 });
15632 </script> 15640 </script>
15633 </dom-module><script> 15641 </dom-module><script>
15634 15642
15635 /** 15643 /**
15636 * @param {!Function} selectCallback 15644 * @param {!Function} selectCallback
15637 * @constructor 15645 * @constructor
15638 */ 15646 */
15639 Polymer.IronSelection = function(selectCallback) { 15647 Polymer.IronSelection = function(selectCallback) {
(...skipping 5272 matching lines...) Expand 10 before | Expand all | Expand 10 after
20912 // Since they will be or'd together, order doesn't matter. 20920 // Since they will be or'd together, order doesn't matter.
20913 var filterGroups = {}; 20921 var filterGroups = {};
20914 this._filters.forEach(function(filterString){ 20922 this._filters.forEach(function(filterString){
20915 var idx = filterString.indexOf(FILTER_SEP); 20923 var idx = filterString.indexOf(FILTER_SEP);
20916 var primary = filterString.slice(0, idx); 20924 var primary = filterString.slice(0, idx);
20917 var param = filterString.slice(idx + FILTER_SEP.length); 20925 var param = filterString.slice(idx + FILTER_SEP.length);
20918 var arr = filterGroups[primary] || []; 20926 var arr = filterGroups[primary] || [];
20919 arr.push(param); 20927 arr.push(param);
20920 filterGroups[primary] = arr; 20928 filterGroups[primary] = arr;
20921 }); 20929 });
20922 return { 20930 return function(bot){
20923 filter: function(bot){ 20931 var retVal = true;
20924 var retVal = true; 20932 // Look up all the primary keys we are filter by, then look up how
20925 // Look up all the primary keys we are filter by, then look up how 20933 // to filter (in filterMap) and apply the filter for each filter
20926 // to filter (in filterMap) and apply the filter for each filter 20934 // option.
20927 // option. 20935 for (primary in filterGroups){
20928 for (primary in filterGroups){ 20936 var params = filterGroups[primary];
20929 var params = filterGroups[primary]; 20937 var filter = filterMap[primary];
20930 var filter = filterMap[primary]; 20938 var groupResult = false;
20931 var groupResult = false; 20939 if (filter) {
20932 if (filter) { 20940 params.forEach(function(param){
20933 params.forEach(function(param){ 20941 groupResult = groupResult || filter.bind(this)(bot,param);
20934 groupResult = groupResult || filter.bind(this)(bot,param); 20942 }.bind(this));
20935 }.bind(this));
20936 }
20937 retVal = retVal && groupResult;
20938 } 20943 }
20939 return retVal; 20944 retVal = retVal && groupResult;
20940 } 20945 }
20946 return retVal;
20941 } 20947 }
20942 }, 20948 },
20943 20949
20944 _primary: function(query, primary_map, primary_arr) { 20950 _primary: function(query, primary_map, primary_arr) {
20945 // If the user has typed in a query, only show those primary keys that 20951 // If the user has typed in a query, only show those primary keys that
20946 // partially match the query or that have secondary values which 20952 // partially match the query or that have secondary values which
20947 // partially match. 20953 // partially match.
20948 var arr = this.primary_arr.filter(function(s){ 20954 var arr = this.primary_arr.filter(function(s){
20949 if (matchPartCaseInsensitive(s, query).idx !== -1) { 20955 if (matchPartCaseInsensitive(s, query).idx !== -1) {
20950 return true; 20956 return true;
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
21144 21150
21145 _gpuAlias: function(gpu) { 21151 _gpuAlias: function(gpu) {
21146 var a = GPU_ALIASES[gpu]; 21152 var a = GPU_ALIASES[gpu];
21147 if (!a) { 21153 if (!a) {
21148 return "UNKNOWN"; 21154 return "UNKNOWN";
21149 } 21155 }
21150 return a; 21156 return a;
21151 }, 21157 },
21152 21158
21153 _not: function(a) { 21159 _not: function(a) {
21154 return a; 21160 return !a;
21161 },
21162
21163 _or: function() {
21164 var result = false;
21165 // can't use .foreach, as arguments isn't really a function.
21166 for (var i = 0; i < arguments.length; i++) {
21167 result = result || arguments[i];
21168 }
21169 return result;
21155 }, 21170 },
21156 21171
21157 _taskId: function(bot) { 21172 _taskId: function(bot) {
21158 if (bot && bot.task_id) { 21173 if (bot && bot.task_id) {
21159 return bot.task_id; 21174 return bot.task_id;
21160 } 21175 }
21161 return "idle"; 21176 return "idle";
21162 }, 21177 },
21163 21178
21164 // _unalias will return the base dimension/state with its alias removed 21179 // _unalias will return the base dimension/state with its alias removed
21165 // if it had one. This is handy for sorting and filtering. 21180 // if it had one. This is handy for sorting and filtering.
21166 _unalias: function(str) { 21181 _unalias: function(str) {
21167 var match = ALIAS_REGEXP.exec(str); 21182 var match = ALIAS_REGEXP.exec(str);
21168 if (match) { 21183 if (match) {
21169 return match[1]; 21184 return match[1];
21170 } 21185 }
21171 return str; 21186 return str;
21172 }, 21187 },
21173 } 21188 }
21174 })() 21189 })()
21175 </script> 21190 </script>
21176 <dom-module id="bot-list-data" assetpath="/res/imp/botlist/"> 21191 <dom-module id="bot-list-data" assetpath="/res/imp/botlist/">
21177 <template> 21192 <template>
21178 <iron-ajax id="request" url="/_ah/api/swarming/v1/bots/list" headers="[[auth _headers]]" handle-as="json" last-response="{{_data}}" loading="{{busy}}"> 21193 <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth _headers]]" handle-as="json" last-response="{{_list}}" loading="{{_busy1}}">
21194 </iron-ajax>
21195
21196 <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_ headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy2}}">
21179 </iron-ajax> 21197 </iron-ajax>
21180 </template> 21198 </template>
21181 <script> 21199 <script>
21182 (function(){ 21200 (function(){
21183 // TODO(kjlubick): Add more of these as well as things from state 21201 // TODO(kjlubick): Add more of these as well as things from state
21184 // i.e. disk space remaining. 21202 // i.e. disk space remaining.
21185 var DIMENSIONS = ["cores", "cpu", "id", "os", "pool"]; 21203 var DIMENSIONS = ["cores", "cpu", "id", "os", "pool"];
21186 // "gpu" and "devices" are added separately because we need to 21204 // "gpu" and "devices" are added separately because we need to
21187 // deal with aliases. 21205 // deal with aliases.
21188 var BOT_PROPERTIES = ["gpu", "devices", "task", "status"]; 21206 var BOT_PROPERTIES = ["gpu", "devices", "task", "status"];
21189 Polymer({ 21207 Polymer({
21190 is: 'bot-list-data', 21208 is: 'bot-list-data',
21209
21210 behaviors: [SwarmingBehaviors.BotListBehavior],
21211
21191 properties: { 21212 properties: {
21192 // inputs 21213 // inputs
21193 auth_headers: { 21214 auth_headers: {
21194 type: Object, 21215 type: Object,
21195 observer: "signIn", 21216 observer: "signIn",
21196 }, 21217 },
21197 21218
21198 //outputs 21219 //outputs
21199 bots: { 21220 bots: {
21200 type: Array, 21221 type: Array,
21201 computed: "_bots(_data)", 21222 computed: "_bots(_list)",
21202 notify: true, 21223 notify: true,
21203 }, 21224 },
21204 busy: { 21225 busy: {
21205 type: Boolean, 21226 type: Boolean,
21227 computed: "_or(_busy1,_busy2)",
21228 notify: true,
21229 },
21230 fleet: {
21231 type: Object,
21232 computed: "_fleet(_count)",
21206 notify: true, 21233 notify: true,
21207 }, 21234 },
21208 primary_map: { 21235 primary_map: {
21209 type:Object, 21236 type:Object,
21210 computed: "_primaryMap(bots)", 21237 computed: "_primaryMap(bots)",
21211 notify: true, 21238 notify: true,
21212 }, 21239 },
21213 primary_arr: { 21240 primary_arr: {
21214 type:Array, 21241 type:Array,
21215 value: function() { 21242 value: function() {
21216 return DIMENSIONS.concat(BOT_PROPERTIES); 21243 return DIMENSIONS.concat(BOT_PROPERTIES);
21217 }, 21244 },
21218 notify: true, 21245 notify: true,
21219 }, 21246 },
21220 21247
21221 // private 21248 // private
21222 _data: { 21249 _count: {
21250 type: Object,
21251 },
21252 _list: {
21223 type: Object, 21253 type: Object,
21224 }, 21254 },
21225 }, 21255 },
21226 behaviors: [SwarmingBehaviors.BotListBehavior],
21227 21256
21228 signIn: function(){ 21257 signIn: function(){
21229 this.$.request.generateRequest(); 21258 this.$.botlist.generateRequest();
21259 this.$.fleet.generateRequest();
21230 }, 21260 },
21231 21261
21232 _bots: function(){ 21262 _bots: function(){
21233 if (!this._data || !this._data.items) { 21263 if (!this._list || !this._list.items) {
21234 return []; 21264 return [];
21235 } 21265 }
21236 this._data.items.forEach(function(o){ 21266 this._list.items.forEach(function(o){
21237 o.state = JSON.parse(o.state); 21267 o.state = JSON.parse(o.state);
21238 }); 21268 });
21239 return this._data.items; 21269 return this._list.items;
21270 },
21271
21272 _fleet: function() {
21273 if (!this._count) {
21274 return {};
21275 }
21276 return {
21277 alive: this._count.count || -1,
21278 busy: this._count.busy || -1,
21279 idle: this._count.count && this._count.busy &&
21280 this._count.count - this._count.busy,
21281 dead: this._count.dead || -1,
21282 quarantined: this._count.quarantined || -1,
21283 }
21240 }, 21284 },
21241 21285
21242 _primaryMap: function(bots){ 21286 _primaryMap: function(bots){
21243 // map will keep track of dimensions that we have seen at least once. 21287 // map will keep track of dimensions that we have seen at least once.
21244 // This will then basically get turned into an array to be used for 21288 // This will then basically get turned into an array to be used for
21245 // filtering. 21289 // filtering.
21246 var map = {}; 21290 var map = {};
21247 DIMENSIONS.forEach(function(p){ 21291 DIMENSIONS.forEach(function(p){
21248 map[p] = {}; 21292 map[p] = {};
21249 }); 21293 });
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
21290 21334
21291 // Create custom filter options 21335 // Create custom filter options
21292 pMap["task"] = ["busy", "idle"]; 21336 pMap["task"] = ["busy", "idle"];
21293 pMap["status"] = ["available", "dead", "quarantined"]; 21337 pMap["status"] = ["available", "dead", "quarantined"];
21294 return pMap; 21338 return pMap;
21295 }, 21339 },
21296 21340
21297 }); 21341 });
21298 })(); 21342 })();
21299 </script> 21343 </script>
21344 </dom-module><dom-module id="bot-list-summary" assetpath="/res/imp/botlist/">
21345 <template>
21346 <style include="swarming-app-style">
21347 :host {
21348 display: block;
21349 border-left: 1px solid black;
21350 padding: 1px 5px;
21351 font-family: sans-serif;
21352 }
21353 .header {
21354 font-size: 1.2em;
21355 font-weight: bold;
21356 }
21357 ul {
21358 list-style-type: none;
21359 }
21360 </style>
21361
21362 <div class="header">Fleet</div>
21363
21364 <ul>
21365 <li><a href="/newui/botlist?alive">Bots Alive</a>: [[fleet.alive]]</li>
21366 <li><a href="/newui/botlist?busy">Bots Busy</a>: [[fleet.busy]]</li>
21367 <li><a href="/newui/botlist?idle">Bots Idle</a>: [[fleet.idle]]</li>
21368 <li><a href="/newui/botlist?dead">Bots Dead</a>: [[fleet.dead]]</li>
21369 <li><a href="/newui/botlist?quaren">Bots Quarantined</a>: [[fleet.quaranti ned]]</li>
21370 </ul>
21371
21372 <div class="header">Currently Showing</div>
21373 <ul>
21374 <li><a href="/newui/botlist?alive2">Bots Alive</a>: [[_currently_showing.a live]]</li>
21375 <li><a href="/newui/botlist?busy2">Bots Busy</a>: [[_currently_showing.bus y]]</li>
21376 <li><a href="/newui/botlist?idle2">Bots Idle</a>: [[_currently_showing.idl e]]</li>
21377 <li><a href="/newui/botlist?dead2">Bots Dead</a>: [[_currently_showing.dea d]]</li>
21378 <li><a href="/newui/botlist?quaren2">Bots Quarantined</a>: [[_currently_sh owing.quarantined]]</li>
21379 </ul>
21380
21381 </template>
21382 <script>
21383 Polymer({
21384 is: 'bot-list-summary',
21385
21386 behaviors: [SwarmingBehaviors.BotListBehavior],
21387
21388 properties: {
21389 filtered_bots: {
21390 type: Array,
21391 },
21392 fleet: {
21393 type: Object,
21394 },
21395
21396 _currently_showing: {
21397 type: Object,
21398 value: function() {
21399 return {
21400 alive: -1,
21401 busy: -1,
21402 idle: -1,
21403 dead: -1,
21404 quarantined: -1,
21405 };
21406 },
21407 },
21408 },
21409
21410 // Do this because Array changes in Polymer don't always trigger normal
21411 // property observers
21412 observers: ["_recount(filtered_bots.*)"],
21413
21414 _recount: function() {
21415 var curr = {
21416 alive: 0,
21417 busy: 0,
21418 idle: 0,
21419 dead: 0,
21420 quarantined: 0,
21421 };
21422 if (!this.filtered_bots) {
21423 return curr;
21424 }
21425 this.filtered_bots.forEach(function(bot) {
21426 if (this._taskId(bot) === "idle") {
21427 curr.idle++;
21428 } else {
21429 curr.busy++;
21430 }
21431 if (bot.quarantined) {
21432 curr.quarantined++;
21433 }
21434 if (bot.is_dead) {
21435 curr.dead++;
21436 } else {
21437 curr.alive++;
21438 }
21439 }.bind(this));
21440 this.set("_currently_showing", curr);
21441 }
21442 });
21443 </script>
21300 </dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/"> 21444 </dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/">
21301 <template> 21445 <template>
21302 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style"> 21446 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style">
21303 bot-filters { 21447 bot-filters, bot-list-summary {
21304 margin-bottom: 5px; 21448 margin-bottom: 5px;
21449 margin-right: 5px;
21305 } 21450 }
21306 .bot { 21451 .bot {
21307 margin:5px; 21452 margin:5px;
21308 max-width:400px; 21453 max-width:400px;
21309 min-height:100px; 21454 min-height:100px;
21310 min-width:300px; 21455 min-width:300px;
21311 } 21456 }
21312 table { 21457 table {
21313 border-collapse: collapse; 21458 border-collapse: collapse;
21314 margin-left: 5px; 21459 margin-left: 5px;
(...skipping 17 matching lines...) Expand all
21332 position: absolute; 21477 position: absolute;
21333 right: 0; 21478 right: 0;
21334 top: 0.4em; 21479 top: 0.4em;
21335 } 21480 }
21336 .bot-list th > span { 21481 .bot-list th > span {
21337 /* Leave space for sort-toggle*/ 21482 /* Leave space for sort-toggle*/
21338 padding-right: 30px; 21483 padding-right: 30px;
21339 } 21484 }
21340 </style> 21485 </style>
21341 21486
21342 <swarming-app auth_headers="{{auth_headers}}" busy="[[busy]]" name="Swarming Bot List"> 21487 <swarming-app auth_headers="{{auth_headers}}" signed_in="{{signed_in}}" busy ="[[busy]]" name="Swarming Bot List">
21343 21488
21344 <bot-filters primary_map="[[primary_map]]" primary_arr="[[primary_arr]]" c olumns="{{columns}}" filter="{{filter}}" verbose="{{verbose}}"> 21489 <h2 hidden$="[[signed_in]]">You must sign in to see anything useful.</h2>
21345 </bot-filters>
21346 21490
21347 <bot-list-data auth_headers="[[auth_headers]]" bots="{{bots}}" busy="{{bus y}}" primary_map="{{primary_map}}" primary_arr="{{primary_arr}}"> 21491 <div hidden$="[[_not(signed_in)]]">
21348 </bot-list-data>
21349 21492
21350 <table class="bot-list"> 21493 <div class="horizontal layout">
21351 <thead on-sort_change="sortChange"> 21494
21352 21495 <bot-filters primary_map="[[primary_map]]" primary_arr="[[primary_arr] ]" columns="{{columns}}" filter="{{filter}}" verbose="{{verbose}}">
21353 <tr><th> 21496 </bot-filters>
21354 <span>Bot Id</span> 21497
21355 <sort-toggle name="id" current="[[sort]]"> 21498 <bot-list-summary fleet="[[fleet]]" filtered_bots="[[filteredSortedBot s]]">
21356 </sort-toggle> 21499 </bot-list-summary>
21357 </th> 21500
21501 </div>
21502
21503 <bot-list-data auth_headers="[[auth_headers]]" bots="{{bots}}" busy="{{b usy}}" fleet="{{fleet}}" primary_map="{{primary_map}}" primary_arr="{{primary_ar r}}">
21504 </bot-list-data>
21505
21506 <table class="bot-list">
21507 <thead on-sort_change="sortChange">
21358 21508
21359 <th hidden$="[[_hide('task', columns.*)]]"> 21509 <tr><th>
21360 <span>Current Task</span> 21510 <span>Bot Id</span>
21361 <sort-toggle name="task" current="[[sort]]"> 21511 <sort-toggle name="id" current="[[sort]]">
21362 </sort-toggle>
21363 </th>
21364
21365 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21366 <th hidden$="[[_hide(c)]]">
21367 <span>[[_header(c)]]</span>
21368 <sort-toggle name="[[c]]" current="[[sort]]">
21369 </sort-toggle> 21512 </sort-toggle>
21370 </th> 21513 </th>
21371 </template> 21514
21372 </tr></thead> 21515 <th hidden$="[[_hide('task', columns.*)]]">
21373 <tbody> 21516 <span>Current Task</span>
21374 <template id="bot_table" is="dom-repeat" items="[[bots]]" as="bot" ini tial-count="50" filter="_filterBotTable"> 21517 <sort-toggle name="task" current="[[sort]]">
21518 </sort-toggle>
21519 </th>
21375 21520
21376 <tr class$="[[_botClass(bot)]]"> 21521 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21377 <td> 21522 <th hidden$="[[_hide(c)]]">
21378 <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_blan k"> 21523 <span>[[_header(c)]]</span>
21379 [[bot.bot_id]] 21524 <sort-toggle name="[[c]]" current="[[sort]]">
21380 </a> 21525 </sort-toggle>
21381 </td> 21526 </th>
21382 <td hidden$="[[_hide('task', columns.*)]]"> 21527 </template>
21383 <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a> 21528 </tr></thead>
21384 </td> 21529 <tbody>
21530 <template id="bot_table" is="dom-repeat" items="[[filteredSortedBots ]]" as="bot" initial-count="50">
21385 21531
21386 <template is="dom-repeat" items="[[plain_columns]]" as="c"> 21532 <tr class$="[[_botClass(bot)]]">
21387 <td hidden$="[[_hide(c)]]"> 21533 <td>
21388 [[_column(c, bot, verbose)]] 21534 <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_bl ank">
21535 [[bot.bot_id]]
21536 </a>
21389 </td> 21537 </td>
21390 </template> 21538 <td hidden$="[[_hide('task', columns.*)]]">
21539 <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a>
21540 </td>
21391 21541
21392 </tr>
21393 <template is="dom-repeat" items="[[_devices(bot)]]" as="device">
21394 <tr hidden$="[[_hide('devices', columns.*)]]" class$="[[_deviceCla ss(device)]]">
21395 <td></td>
21396 <td hidden$="[[_hide('task', columns.*)]]"></td>
21397 <template is="dom-repeat" items="[[plain_columns]]" as="c"> 21542 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21398 <td hidden$="[[_hide(c)]]"> 21543 <td hidden$="[[_hide(c)]]">
21399 [[_deviceColumn(c, device, verbose)]] 21544 [[_column(c, bot, verbose)]]
21400 </td> 21545 </td>
21401 </template> 21546 </template>
21547
21402 </tr> 21548 </tr>
21549 <template is="dom-repeat" items="[[_devices(bot)]]" as="device">
21550 <tr hidden$="[[_hide('devices', columns.*)]]" class$="[[_deviceC lass(device)]]">
21551 <td></td>
21552 <td hidden$="[[_hide('task', columns.*)]]"></td>
21553 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21554 <td hidden$="[[_hide(c)]]">
21555 [[_deviceColumn(c, device, verbose)]]
21556 </td>
21557 </template>
21558 </tr>
21559 </template>
21403 </template> 21560 </template>
21404 </template> 21561 </tbody>
21405 </tbody> 21562 </table>
21406 </table> 21563 </div>
21407 21564
21408 </swarming-app> 21565 </swarming-app>
21409 21566
21410 </template> 21567 </template>
21411 <script> 21568 <script>
21412 (function(){ 21569 (function(){
21413 var special_columns = ["id", "task"]; 21570 var special_columns = ["id", "task"];
21414 21571
21415 var headerMap = { 21572 var headerMap = {
21416 // "id" and "task" are special, so they don't go here and have their 21573 // "id" and "task" are special, so they don't go here and have their
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
21502 return this._taskId(bot); 21659 return this._taskId(bot);
21503 }, 21660 },
21504 }; 21661 };
21505 21662
21506 Polymer({ 21663 Polymer({
21507 is: 'bot-list', 21664 is: 'bot-list',
21508 behaviors: [SwarmingBehaviors.BotListBehavior], 21665 behaviors: [SwarmingBehaviors.BotListBehavior],
21509 21666
21510 properties: { 21667 properties: {
21511 21668
21669 bots: {
21670 type: Array,
21671 },
21672
21512 columns: { 21673 columns: {
21513 type: Array, 21674 type: Array,
21514 }, 21675 },
21515 // Should have a property "filter" which is a function. 21676
21516 filter: { 21677 filter: {
21517 type: Object, 21678 type: Function,
21679 value: function() {
21680 return true;
21681 },
21682 },
21683
21684 filteredSortedBots: {
21685 type: Array,
21686 computed: "_filterAndSort(bots,filter.*,sort.*)"
21518 }, 21687 },
21519 21688
21520 plain_columns: { 21689 plain_columns: {
21521 type: Array, 21690 type: Array,
21522 computed: "_stripSpecial(columns.*)", 21691 computed: "_stripSpecial(columns.*)",
21523 }, 21692 },
21524 21693
21525 // sort is an Object {name:String, direction:String}. 21694 // sort is an Object {name:String, direction:String}.
21526 sort: { 21695 sort: {
21527 type: Object, 21696 type: Object,
21697 value: function() {
21698 return {
21699 name: "id",
21700 direction: "asc",
21701 };
21702 }
21528 }, 21703 },
21529 21704
21530 verbose: { 21705 verbose: {
21531 type: Boolean, 21706 type: Boolean,
21532 } 21707 }
21533 }, 21708 },
21534 21709
21535 observers: [
21536 '_reRender(filter.*)',
21537 '_checkSorts(columns.*)'
21538 ],
21539
21540 _botClass: function(bot) { 21710 _botClass: function(bot) {
21541 if (bot.is_dead) { 21711 if (bot.is_dead) {
21542 return "dead"; 21712 return "dead";
21543 } 21713 }
21544 if (bot.quarantined) { 21714 if (bot.quarantined) {
21545 return "quarantined"; 21715 return "quarantined";
21546 } 21716 }
21547 return ""; 21717 return "";
21548 }, 21718 },
21549 21719
21550 _botLink: function(id) { 21720 _botLink: function(id) {
21551 // TODO(kjlubick) Make this point to /newui/ when appropriate. 21721 // TODO(kjlubick) Make this point to /newui/ when appropriate.
21552 return "/restricted/bot/"+id; 21722 return "/restricted/bot/"+id;
21553 }, 21723 },
21554 21724
21555 // _checkSorts makes sure that if a column has been removed, the related
21556 // sort is also removed.
21557 _checkSorts: function() {
21558 if (!this.sort) {
21559 return;
21560 }
21561 this._reRender();
21562 },
21563 21725
21564 _column: function(col, bot) { 21726 _column: function(col, bot) {
21565 return columnMap[col].bind(this)(bot); 21727 return columnMap[col].bind(this)(bot);
21566 }, 21728 },
21567 21729
21568 _deviceColumn: function(col, device) { 21730 _deviceColumn: function(col, device) {
21569 if (col === "devices") { 21731 if (col === "devices") {
21570 var str = this._androidAlias(device); 21732 var str = this._androidAlias(device);
21571 if (device.okay) { 21733 if (device.okay) {
21572 str = this._applyAlias(this._deviceType(device), str); 21734 str = this._applyAlias(this._deviceType(device), str);
21573 } 21735 }
21574 str += " S/N:"; 21736 str += " S/N:";
21575 str += device.serial; 21737 str += device.serial;
21576 return str; 21738 return str;
21577 } 21739 }
21578 if (col === "status") { 21740 if (col === "status") {
21579 return device.state; 21741 return device.state;
21580 } 21742 }
21581 return ""; 21743 return "";
21582 }, 21744 },
21583 21745
21584 _deviceClass: function(device) { 21746 _deviceClass: function(device) {
21585 if (!device.okay) { 21747 if (!device.okay) {
21586 return "bad-device"; 21748 return "bad-device";
21587 } 21749 }
21588 return ""; 21750 return "";
21589 }, 21751 },
21590 21752
21591 _filterBotTable: function(bot) { 21753 _filterAndSort: function(a,b,c) {
21592 if (!this.filter || !this.filter.filter) { 21754 // We intentionally sort this.bots (and not a copy) to allow users to
21593 return true; 21755 // "chain" sorts, that is, sort by one thing and then another, and
21756 // have both orderings properly impact the list.
21757 swarming.stableSort(this.bots, this._sortBotTable.bind(this));
21758 var bots = this.bots;
21759 if (this.filter) {
21760 bots = bots.filter(this.filter.bind(this));
21594 } 21761 }
21595 return this.filter.filter.bind(this)(bot); 21762
21763 return bots;
21596 }, 21764 },
21597 21765
21598 _header: function(col){ 21766 _header: function(col){
21599 return headerMap[col]; 21767 return headerMap[col];
21600 }, 21768 },
21601 21769
21602 _hide: function(col) { 21770 _hide: function(col) {
21603 return this.columns.indexOf(col) === -1; 21771 return this.columns.indexOf(col) === -1;
21604 }, 21772 },
21605 21773
(...skipping 14 matching lines...) Expand all
21620 21788
21621 return dir * swarming.naturalCompare(botACol, botBCol); 21789 return dir * swarming.naturalCompare(botACol, botBCol);
21622 }, 21790 },
21623 21791
21624 sortChange: function(e) { 21792 sortChange: function(e) {
21625 // The event we get from sort-toggle tells us the name of what needs 21793 // The event we get from sort-toggle tells us the name of what needs
21626 // to be sorting and how to sort it. 21794 // to be sorting and how to sort it.
21627 if (!(e && e.detail && e.detail.name)) { 21795 if (!(e && e.detail && e.detail.name)) {
21628 return; 21796 return;
21629 } 21797 }
21798 // should trigger __filterAndSort
21630 this.set("sort", e.detail); 21799 this.set("sort", e.detail);
21631 swarming.stableSort(this.bots, this._sortBotTable.bind(this));
21632 this._reRender();
21633 }, 21800 },
21634 21801
21635 // _stripSpecial removes the special columns and sorts the remaining 21802 // _stripSpecial removes the special columns and sorts the remaining
21636 // columns so they always appear in the same order, regardless of 21803 // columns so they always appear in the same order, regardless of
21637 // the order they are added. 21804 // the order they are added.
21638 _stripSpecial: function(){ 21805 _stripSpecial: function(){
21639 return this.columns.filter(function(c){ 21806 return this.columns.filter(function(c){
21640 return special_columns.indexOf(c) === -1; 21807 return special_columns.indexOf(c) === -1;
21641 }).sort(); 21808 }).sort();
21642 }, 21809 },
21643 21810
21644 _taskLink: function(data) { 21811 _taskLink: function(data) {
21645 if (data && data.task_id) { 21812 if (data && data.task_id) {
21646 return "/user/task/" + data.task_id; 21813 return "/user/task/" + data.task_id;
21647 } 21814 }
21648 return undefined; 21815 return undefined;
21649 } 21816 }
21650 21817
21651 }); 21818 });
21652 })(); 21819 })();
21653 </script> 21820 </script>
21654 </dom-module></div></body></html> 21821 </dom-module></div></body></html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698