Chromium Code Reviews| Index: appengine/swarming/elements/res/imp/botlist/bot-list.html |
| diff --git a/appengine/swarming/elements/res/imp/botlist/bot-list.html b/appengine/swarming/elements/res/imp/botlist/bot-list.html |
| index d5d723f1c1055c376c189a92061889dfa1f53036..198bb2d47b50a22366c589f5d55da187e6f81cd1 100644 |
| --- a/appengine/swarming/elements/res/imp/botlist/bot-list.html |
| +++ b/appengine/swarming/elements/res/imp/botlist/bot-list.html |
| @@ -30,13 +30,14 @@ |
| <link rel="import" href="bot-filters.html"> |
| <link rel="import" href="bot-list-data.html"> |
| <link rel="import" href="bot-list-shared.html"> |
| - |
| +<link rel="import" href="bot-list-summary.html"> |
| <dom-module id="bot-list"> |
| <template> |
| <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style"> |
| - bot-filters { |
| + bot-filters, bot-list-summary { |
| margin-bottom: 5px; |
| + margin-right: 5px; |
| } |
| .bot { |
| margin:5px; |
| @@ -76,115 +77,131 @@ |
| <swarming-app |
| auth_headers="{{auth_headers}}" |
| + signed_in="{{signed_in}}" |
| + |
| 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"> |
| - <!-- To allow for dynamic columns without having a lot of copy-pasted |
| - code, we break columns up into "special" and "plain" columns. Special |
| - columns require some sort of HTML output (e.g. anchor tags) and plain |
| - columns just output text. The plain columns use Polymer functions to |
| - insert their text [_header(), _column(), _deviceColumn()]. Polymer |
| - functions do not allow HTML (to avoid XSS), so special columns, like id |
| - and task are inserted in a fixed order. |
| - --> |
| - <th> |
| - <span>Bot Id</span> |
| - <sort-toggle |
| - name="id" |
| - current="[[sort]]"> |
| - </sort-toggle> |
| - </th> |
| - <!-- This wonky syntax is the proper way to listen to changes on an |
| - array (we are listening to all subproperties). The element returned is |
| - not of much use, so we'll ignore it in _hide() and use this.columns. |
| + <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"> |
|
stephana
2016/08/02 14:00:29
There should be a <tr> element wrapping the <th> e
kjlubick
2016/08/03 12:52:30
Done.
|
| + <!-- To allow for dynamic columns without having a lot of copy-pasted |
| + code, we break columns up into "special" and "plain" columns. Special |
| + columns require some sort of HTML output (e.g. anchor tags) and plain |
| + columns just output text. The plain columns use Polymer functions to |
| + insert their text [_header(), _column(), _deviceColumn()]. Polymer |
| + functions do not allow HTML (to avoid XSS), so special columns, like id |
| + and task are inserted in a fixed order. |
| --> |
| - <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> |
| + <th> |
| + <span>Bot Id</span> |
| <sort-toggle |
| - name="[[c]]" |
| + name="id" |
| + current="[[sort]]"> |
| + </sort-toggle> |
| + </th> |
| + <!-- This wonky syntax is the proper way to listen to changes on an |
| + array (we are listening to all subproperties). The element returned is |
| + not of much use, so we'll ignore it in _hide() and use this.columns. |
| + --> |
| + <th hidden$="[[_hide('task', columns.*)]]"> |
| + <span>Current Task</span> |
| + <sort-toggle |
| + name="task" |
| current="[[sort]]"> |
| </sort-toggle> |
| </th> |
| - </template> |
| - </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> |
| - </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> |
| + items="[[plain_columns]]" |
| + as="c"> |
| + <th hidden$="[[_hide(c)]]"> |
| + <span>[[_header(c)]]</span> |
| + <sort-toggle |
| + name="[[c]]" |
| + current="[[sort]]"> |
| + </sort-toggle> |
| + </th> |
| + </template> |
| + </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> <!--devices repeat--> |
| - </template> <!--bot-table repeat--> |
| - </tbody> |
| - </table> |
| + <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> <!--devices repeat--> |
| + </template> <!--bot-table repeat--> |
| + </tbody> |
| + </table> |
| + </div> |
| </swarming-app> |
| @@ -290,12 +307,24 @@ |
| properties: { |
| + bots: { |
| + type: Array, |
| + }, |
| + |
| columns: { |
| type: Array, |
| }, |
| - // Should have a property "filter" which is a function. |
| + |
| filter: { |
|
stephana
2016/08/02 14:00:29
If these are exposed properties then they should b
kjlubick
2016/08/03 12:52:30
Done.
|
| - type: Object, |
| + type: Function, |
| + value: function() { |
| + return true; |
| + }, |
| + }, |
| + |
| + filteredSortedBots: { |
| + type: Array, |
| + computed: "_filterAndSort(bots,filter.*,sort.*)" |
| }, |
| plain_columns: { |
| @@ -306,6 +335,12 @@ |
| // sort is an Object {name:String, direction:String}. |
| sort: { |
| type: Object, |
| + value: function() { |
| + return { |
| + name: "id", |
| + direction: "asc", |
| + }; |
| + } |
| }, |
| verbose: { |
| @@ -313,11 +348,6 @@ |
| } |
| }, |
| - observers: [ |
| - '_reRender(filter.*)', |
| - '_checkSorts(columns.*)' |
| - ], |
| - |
| _botClass: function(bot) { |
| if (bot.is_dead) { |
| return "dead"; |
| @@ -333,14 +363,6 @@ |
| 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); |
| @@ -369,11 +391,17 @@ |
| 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){ |
| @@ -408,9 +436,8 @@ |
| if (!(e && e.detail && e.detail.name)) { |
| return; |
| } |
| + // should trigger __filterAndSort |
| this.set("sort", e.detail); |
| - swarming.stableSort(this.bots, this._sortBotTable.bind(this)); |
| - this._reRender(); |
| }, |
| // _stripSpecial removes the special columns and sorts the remaining |