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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « appengine/swarming/elements/Makefile ('k') | appengine/swarming/elements/build/js/common.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/swarming/elements/build/elements.html
diff --git a/appengine/swarming/elements/build/elements.html b/appengine/swarming/elements/build/elements.html
index 6979e82b5e0feb0d9fa6d2ce9c2edd51c9f55a1e..b6428c3f6474354a74649176d7d2baa72c0a3625 100644
--- a/appengine/swarming/elements/build/elements.html
+++ b/appengine/swarming/elements/build/elements.html
@@ -14496,7 +14496,8 @@ You can bind to `isAuthorized` property to monitor authorization state.
signedIn: {
type: Boolean,
readOnly: true,
- value: false
+ value: false,
+ notify: true,
}
},
@@ -14509,6 +14510,7 @@ You can bind to `isAuthorized` property to monitor authorization state.
imageUrl: profile.getImageUrl()
});
this.set("authResponse", user.getAuthResponse());
+ this._setSignedIn(true);
this.fire("auth-signin");
},
@@ -14582,7 +14584,7 @@ You can bind to `isAuthorized` property to monitor authorization state.
<a class="left" href="/newui/botlist">Bot List</a>
<div class="flex"></div>
- <auth-signin class="right" client-id="20770472288-t5smpbpjptka4nd888fv0ctd23ftba2o.apps.googleusercontent.com" auth-headers="{{auth_headers}}">
+ <auth-signin class="right" client-id="20770472288-t5smpbpjptka4nd888fv0ctd23ftba2o.apps.googleusercontent.com" auth-headers="{{auth_headers}}" signed-in="{{signed_in}}">
</auth-signin>
</app-toolbar>
</app-header>
@@ -14600,6 +14602,12 @@ You can bind to `isAuthorized` property to monitor authorization state.
type: Object,
notify: true,
},
+ signed_in: {
+ type: Boolean,
+ value: false,
+ notify:true,
+ },
+
busy: {
type: Boolean,
},
@@ -15582,6 +15590,7 @@ You can bind to `isAuthorized` property to monitor authorization state.
<script>
Polymer({
is: "sort-toggle",
+
properties: {
current: {
type: Object,
@@ -15626,7 +15635,6 @@ You can bind to `isAuthorized` property to monitor authorization state.
} else {
this.set("direction", "");
}
-
},
});
</script>
@@ -20919,25 +20927,23 @@ is separate from validation, and `allowed-pattern` does not affect how the input
arr.push(param);
filterGroups[primary] = arr;
});
- return {
- filter: function(bot){
- var retVal = true;
- // Look up all the primary keys we are filter by, then look up how
- // to filter (in filterMap) and apply the filter for each filter
- // option.
- for (primary in filterGroups){
- var params = filterGroups[primary];
- var filter = filterMap[primary];
- var groupResult = false;
- if (filter) {
- params.forEach(function(param){
- groupResult = groupResult || filter.bind(this)(bot,param);
- }.bind(this));
- }
- retVal = retVal && groupResult;
+ return function(bot){
+ var retVal = true;
+ // Look up all the primary keys we are filter by, then look up how
+ // to filter (in filterMap) and apply the filter for each filter
+ // option.
+ for (primary in filterGroups){
+ var params = filterGroups[primary];
+ var filter = filterMap[primary];
+ var groupResult = false;
+ if (filter) {
+ params.forEach(function(param){
+ groupResult = groupResult || filter.bind(this)(bot,param);
+ }.bind(this));
}
- return retVal;
+ retVal = retVal && groupResult;
}
+ return retVal;
}
},
@@ -21151,7 +21157,16 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
_not: function(a) {
- return a;
+ return !a;
+ },
+
+ _or: function() {
+ var result = false;
+ // can't use .foreach, as arguments isn't really a function.
+ for (var i = 0; i < arguments.length; i++) {
+ result = result || arguments[i];
+ }
+ return result;
},
_taskId: function(bot) {
@@ -21175,7 +21190,10 @@ is separate from validation, and `allowed-pattern` does not affect how the input
</script>
<dom-module id="bot-list-data" assetpath="/res/imp/botlist/">
<template>
- <iron-ajax id="request" url="/_ah/api/swarming/v1/bots/list" headers="[[auth_headers]]" handle-as="json" last-response="{{_data}}" loading="{{busy}}">
+ <iron-ajax id="botlist" url="/_ah/api/swarming/v1/bots/list" headers="[[auth_headers]]" handle-as="json" last-response="{{_list}}" loading="{{_busy1}}">
+ </iron-ajax>
+
+ <iron-ajax id="fleet" url="/_ah/api/swarming/v1/bots/count" headers="[[auth_headers]]" handle-as="json" last-response="{{_count}}" loading="{{_busy2}}">
</iron-ajax>
</template>
<script>
@@ -21188,6 +21206,9 @@ is separate from validation, and `allowed-pattern` does not affect how the input
var BOT_PROPERTIES = ["gpu", "devices", "task", "status"];
Polymer({
is: 'bot-list-data',
+
+ behaviors: [SwarmingBehaviors.BotListBehavior],
+
properties: {
// inputs
auth_headers: {
@@ -21198,11 +21219,17 @@ is separate from validation, and `allowed-pattern` does not affect how the input
//outputs
bots: {
type: Array,
- computed: "_bots(_data)",
+ computed: "_bots(_list)",
notify: true,
},
busy: {
type: Boolean,
+ computed: "_or(_busy1,_busy2)",
+ notify: true,
+ },
+ fleet: {
+ type: Object,
+ computed: "_fleet(_count)",
notify: true,
},
primary_map: {
@@ -21219,24 +21246,41 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
// private
- _data: {
+ _count: {
+ type: Object,
+ },
+ _list: {
type: Object,
},
},
- behaviors: [SwarmingBehaviors.BotListBehavior],
signIn: function(){
- this.$.request.generateRequest();
+ this.$.botlist.generateRequest();
+ this.$.fleet.generateRequest();
},
_bots: function(){
- if (!this._data || !this._data.items) {
+ if (!this._list || !this._list.items) {
return [];
}
- this._data.items.forEach(function(o){
+ this._list.items.forEach(function(o){
o.state = JSON.parse(o.state);
});
- return this._data.items;
+ return this._list.items;
+ },
+
+ _fleet: function() {
+ if (!this._count) {
+ return {};
+ }
+ return {
+ alive: this._count.count || -1,
+ busy: this._count.busy || -1,
+ idle: this._count.count && this._count.busy &&
+ this._count.count - this._count.busy,
+ dead: this._count.dead || -1,
+ quarantined: this._count.quarantined || -1,
+ }
},
_primaryMap: function(bots){
@@ -21297,11 +21341,145 @@ is separate from validation, and `allowed-pattern` does not affect how the input
});
})();
</script>
+</dom-module><dom-module id="bot-list-summary" assetpath="/res/imp/botlist/">
+ <template>
+ <style include="swarming-app-style">
+ :host {
+ display: block;
+ border-left: 1px solid black;
+ padding: 5px 5px;
+ font-family: sans-serif;
+ }
+ .header {
+ font-size: 1.2em;
+ font-weight: bold;
+ }
+ .right {
+ text-align: right;
+ }
+ .left {
+ text-align: left;
+ }
+ </style>
+
+ <div class="header">Fleet</div>
+
+ <table>
+ <tbody><tr>
+ <td class="right"><a href="/newui/botlist?alive">Alive</a>:</td>
+ <td class="left">[[fleet.alive]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?busy">Busy</a>:</td>
+ <td class="left">[[fleet.busy]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?idle">Idle</a>:</td>
+ <td class="left">[[fleet.idle]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?dead">Dead</a>:</td>
+ <td class="left">[[fleet.dead]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?quaren">Quarantined</a>:</td>
+ <td class="left">[[fleet.quarantined]]</td>
+ </tr>
+ </tbody></table>
+
+ <div class="header">Displayed</div>
+ <table>
+ <tbody><tr>
+ <td class="right"><a href="/newui/botlist?alive2">Alive</a>:</td>
+ <td class="left">[[_currently_showing.alive]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?busy2">Busy</a>:</td>
+ <td class="left">[[_currently_showing.busy]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?idle2">Idle</a>:</td>
+ <td class="left">[[_currently_showing.idle]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?dead2">Dead</a>:</td>
+ <td class="left">[[_currently_showing.dead]]</td>
+ </tr>
+ <tr>
+ <td class="right"><a href="/newui/botlist?quaren2">Quarantined</a>:</td>
+ <td class="left">[[_currently_showing.quarantined]]</td>
+ </tr>
+ </tbody></table>
+
+ </template>
+ <script>
+ Polymer({
+ is: 'bot-list-summary',
+
+ behaviors: [SwarmingBehaviors.BotListBehavior],
+
+ properties: {
+ filtered_bots: {
+ type: Array,
+ },
+ fleet: {
+ type: Object,
+ },
+
+ _currently_showing: {
+ type: Object,
+ value: function() {
+ return {
+ alive: -1,
+ busy: -1,
+ idle: -1,
+ dead: -1,
+ quarantined: -1,
+ };
+ },
+ },
+ },
+
+ // Do this because Array changes in Polymer don't always trigger normal
+ // property observers
+ observers: ["_recount(filtered_bots.*)"],
+
+ _recount: function() {
+ var curr = {
+ alive: 0,
+ busy: 0,
+ idle: 0,
+ dead: 0,
+ quarantined: 0,
+ };
+ if (!this.filtered_bots) {
+ return curr;
+ }
+ this.filtered_bots.forEach(function(bot) {
+ if (this._taskId(bot) === "idle") {
+ curr.idle++;
+ } else {
+ curr.busy++;
+ }
+ if (bot.quarantined) {
+ curr.quarantined++;
+ }
+ if (bot.is_dead) {
+ curr.dead++;
+ } else {
+ curr.alive++;
+ }
+ }.bind(this));
+ this.set("_currently_showing", curr);
+ }
+ });
+ </script>
</dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/">
<template>
<style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style">
- bot-filters {
- margin-bottom: 5px;
+ bot-filters, bot-list-summary {
+ margin-bottom: 8px;
+ margin-right: 10px;
}
.bot {
margin:5px;
@@ -21339,71 +21517,85 @@ is separate from validation, and `allowed-pattern` does not affect how the input
}
</style>
- <swarming-app auth_headers="{{auth_headers}}" busy="[[busy]]" name="Swarming Bot List">
-
- <bot-filters primary_map="[[primary_map]]" primary_arr="[[primary_arr]]" columns="{{columns}}" filter="{{filter}}" verbose="{{verbose}}">
- </bot-filters>
-
- <bot-list-data auth_headers="[[auth_headers]]" bots="{{bots}}" busy="{{busy}}" primary_map="{{primary_map}}" primary_arr="{{primary_arr}}">
- </bot-list-data>
-
- <table class="bot-list">
- <thead on-sort_change="sortChange">
-
- <tr><th>
- <span>Bot Id</span>
- <sort-toggle name="id" current="[[sort]]">
- </sort-toggle>
- </th>
+ <swarming-app auth_headers="{{_auth_headers}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Swarming Bot List">
+
+ <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
+
+ <div hidden$="[[_not(_signed_in)]]">
+
+ <div class="horizontal layout">
+
+ <bot-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_arr]]" columns="{{_columns}}" filter="{{_filter}}" verbose="{{_verbose}}">
+ </bot-filters>
+
+ <bot-list-summary fleet="[[_fleet]]" filtered_bots="[[_filteredSortedBots]]">
+ </bot-list-summary>
+
+ </div>
+
+ <bot-list-data auth_headers="[[_auth_headers]]" bots="{{_bots}}" busy="{{_busy}}" fleet="{{_fleet}}" primary_map="{{_primary_map}}" primary_arr="{{_primary_arr}}">
+ </bot-list-data>
+
+ <table class="bot-list">
+ <thead on-sort_change="_sortChange">
- <th hidden$="[[_hide('task', columns.*)]]">
- <span>Current Task</span>
- <sort-toggle name="task" current="[[sort]]">
- </sort-toggle>
- </th>
+ <tr>
+ <th>
+ <span>Bot Id</span>
+ <sort-toggle name="id" current="[[_sort]]">
+ </sort-toggle>
+ </th>
+
+ <th hidden$="[[_hide('task', _columns.*)]]">
+ <span>Current Task</span>
+ <sort-toggle name="task" current="[[_sort]]">
+ </sort-toggle>
+ </th>
- <template is="dom-repeat" items="[[plain_columns]]" as="c">
- <th hidden$="[[_hide(c)]]">
- <span>[[_header(c)]]</span>
- <sort-toggle name="[[c]]" current="[[sort]]">
- </sort-toggle>
- </th>
- </template>
- </tr></thead>
- <tbody>
- <template id="bot_table" is="dom-repeat" items="[[bots]]" as="bot" initial-count="50" filter="_filterBotTable">
-
- <tr class$="[[_botClass(bot)]]">
- <td>
- <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_blank">
- [[bot.bot_id]]
- </a>
- </td>
- <td hidden$="[[_hide('task', columns.*)]]">
- <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a>
- </td>
-
- <template is="dom-repeat" items="[[plain_columns]]" as="c">
- <td hidden$="[[_hide(c)]]">
- [[_column(c, bot, verbose)]]
- </td>
+ <template is="dom-repeat" items="[[_plain_columns]]" as="c">
+ <th hidden$="[[_hide(c)]]">
+ <span>[[_header(c)]]</span>
+ <sort-toggle name="[[c]]" current="[[_sort]]">
+ </sort-toggle>
+ </th>
</template>
-
</tr>
- <template is="dom-repeat" items="[[_devices(bot)]]" as="device">
- <tr hidden$="[[_hide('devices', columns.*)]]" class$="[[_deviceClass(device)]]">
- <td></td>
- <td hidden$="[[_hide('task', columns.*)]]"></td>
- <template is="dom-repeat" items="[[plain_columns]]" as="c">
+ </thead>
+ <tbody>
+ <template id="bot_table" is="dom-repeat" items="[[_filteredSortedBots]]" as="bot" initial-count="50">
+
+ <tr class$="[[_botClass(bot)]]">
+ <td>
+ <a class="center" href$="[[_botLink(bot.bot_id)]]" target="_blank">
+ [[bot.bot_id]]
+ </a>
+ </td>
+ <td hidden$="[[_hide('task', _columns.*)]]">
+ <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a>
+ </td>
+
+ <template is="dom-repeat" items="[[_plain_columns]]" as="c">
<td hidden$="[[_hide(c)]]">
- [[_deviceColumn(c, device, verbose)]]
+ [[_column(c, bot, _verbose)]]
</td>
</template>
+
</tr>
+ <template is="dom-repeat" items="[[_devices(bot)]]" as="device">
+ <tr hidden$="[[_hide('devices', _columns.*)]]" class$="[[_deviceClass(device)]]">
+ <td></td>
+ <td hidden$="[[_hide('task', _columns.*)]]"></td>
+ <template is="dom-repeat" items="[[_plain_columns]]" as="c">
+ <td hidden$="[[_hide(c)]]">
+ [[_deviceColumn(c, device, _verbose)]]
+ </td>
+ </template>
+ </tr>
+ </template>
</template>
- </template>
- </tbody>
- </table>
+ </tbody>
+ </table>
+ </div>
</swarming-app>
@@ -21430,14 +21622,14 @@ is separate from validation, and `allowed-pattern` does not affect how the input
var columnMap = {
cores: function(bot){
var cores = this._cores(bot);
- if (this.verbose){
+ if (this._verbose){
return cores.join(" | ");
}
return cores[0];
},
cpu: function(bot){
var cpus = this._dimension(bot, 'cpu') || ['Unknown'];
- if (this.verbose){
+ if (this._verbose){
return cpus.join(" | ");
}
return cpus[0];
@@ -21468,7 +21660,7 @@ is separate from validation, and `allowed-pattern` does not affect how the input
named.push(this._applyAlias(g, alias));
}
}.bind(this))
- if (this.verbose) {
+ if (this._verbose) {
return verbose.join(" | ");
}
return named.join(" | ");
@@ -21478,7 +21670,7 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
os: function(bot) {
var os = this._dimension(bot, 'os') || ['Unknown'];
- if (this.verbose){
+ if (this._verbose){
return os.join(" | ");
}
return os[0];
@@ -21509,34 +21701,47 @@ is separate from validation, and `allowed-pattern` does not affect how the input
properties: {
- columns: {
+ _bots: {
type: Array,
},
- // Should have a property "filter" which is a function.
- filter: {
- type: Object,
+
+ _columns: {
+ type: Array,
+ },
+
+ _filter: {
+ type: Function,
+ value: function() {
+ return true;
+ },
+ },
+
+ _filteredSortedBots: {
+ type: Array,
+ computed: "_filterAndSort(_bots,_filter.*,_sort.*)"
},
- plain_columns: {
+ _plain_columns: {
type: Array,
- computed: "_stripSpecial(columns.*)",
+ computed: "_stripSpecial(_columns.*)",
},
- // sort is an Object {name:String, direction:String}.
- sort: {
+ // _sort is an Object {name:String, direction:String}.
+ _sort: {
type: Object,
+ value: function() {
+ return {
+ name: "id",
+ direction: "asc",
+ };
+ }
},
- verbose: {
+ _verbose: {
type: Boolean,
}
},
- observers: [
- '_reRender(filter.*)',
- '_checkSorts(columns.*)'
- ],
-
_botClass: function(bot) {
if (bot.is_dead) {
return "dead";
@@ -21552,14 +21757,6 @@ is separate from validation, and `allowed-pattern` does not affect how the input
return "/restricted/bot/"+id;
},
- // _checkSorts makes sure that if a column has been removed, the related
- // sort is also removed.
- _checkSorts: function() {
- if (!this.sort) {
- return;
- }
- this._reRender();
- },
_column: function(col, bot) {
return columnMap[col].bind(this)(bot);
@@ -21588,11 +21785,17 @@ is separate from validation, and `allowed-pattern` does not affect how the input
return "";
},
- _filterBotTable: function(bot) {
- if (!this.filter || !this.filter.filter) {
- return true;
+ _filterAndSort: function(a,b,c) {
+ // We intentionally sort this._bots (and not a copy) to allow users to
+ // "chain" sorts, that is, sort by one thing and then another, and
+ // have both orderings properly impact the list.
+ swarming.stableSort(this._bots, this._sortBotTable.bind(this));
+ var bots = this._bots;
+ if (this._filter) {
+ bots = bots.filter(this._filter.bind(this));
}
- return this.filter.filter.bind(this)(bot);
+
+ return bots;
},
_header: function(col){
@@ -21600,7 +21803,7 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
_hide: function(col) {
- return this.columns.indexOf(col) === -1;
+ return this._columns.indexOf(col) === -1;
},
_reRender: function(filter, sort) {
@@ -21608,35 +21811,34 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
_sortBotTable: function(botA, botB) {
- if (!this.sort) {
+ if (!this._sort) {
return 0;
}
var dir = 1;
- if (this.sort.direction === "desc") {
+ if (this._sort.direction === "desc") {
dir = -1;
}
- var botACol = this._column(this.sort.name, botA);
- var botBCol = this._column(this.sort.name, botB);
+ var botACol = this._column(this._sort.name, botA);
+ var botBCol = this._column(this._sort.name, botB);
return dir * swarming.naturalCompare(botACol, botBCol);
},
- sortChange: function(e) {
+ _sortChange: function(e) {
// The event we get from sort-toggle tells us the name of what needs
// to be sorting and how to sort it.
if (!(e && e.detail && e.detail.name)) {
return;
}
- this.set("sort", e.detail);
- swarming.stableSort(this.bots, this._sortBotTable.bind(this));
- this._reRender();
+ // should trigger __filterAndSort
+ this.set("_sort", e.detail);
},
// _stripSpecial removes the special columns and sorts the remaining
// columns so they always appear in the same order, regardless of
// the order they are added.
_stripSpecial: function(){
- return this.columns.filter(function(c){
+ return this._columns.filter(function(c){
return special_columns.indexOf(c) === -1;
}).sort();
},
« no previous file with comments | « appengine/swarming/elements/Makefile ('k') | appengine/swarming/elements/build/js/common.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698