| OLD | NEW |
| (Empty) | |
| 1 <!-- |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. |
| 3 Use of this source code is governed under the Apache License, Version 2.0 |
| 4 that can be found in the LICENSE file. |
| 5 |
| 6 This file contains most of the logic needed to create a dynamic table. It is b
roken up into two |
| 7 parts, a style dom-module called "dynamic-table-style" and a behavior called |
| 8 SwarmingBehaviors.DynamicTableBehavior. This behavior ties together filtering,
sorting and column |
| 9 content. It also offers a few utilities to make creating the table easier. A c
lient of these two |
| 10 parts needs to create the templates to actually draw the <table>,<tr> and so o
n. See |
| 11 bot-list.html and task-list.html for examples. |
| 12 |
| 13 A client should use the provided style set as follows: |
| 14 |
| 15 <link rel="import" href="/res/imp/common/dynamic-table-behavior.html"> |
| 16 ... |
| 17 <template> |
| 18 <style include="dynamic-table-style"> |
| 19 ... |
| 20 |
| 21 This behavior has already defined the following properties, which a client sho
uld bind to: |
| 22 _columns, Array<String>, The columns that should be shown. |
| 23 _items, Array<Object>, Those elements that may be displayed and/or sorted, d
epending on the |
| 24 settings. |
| 25 _filter, Function, Given an element from _items, return a boolean if the ite
m should be shown. |
| 26 This function will be bound to this element. |
| 27 _sortstr, String, A String representation of the current state of sorting li
ke |
| 28 [name]:["asc", "desc"]. |
| 29 _verbose, Boolean, If the verbose contents of the table should be shown. |
| 30 |
| 31 A client must define the following properties: |
| 32 _columnMap: Object, a mapping of column name to a function that will return
the content for a |
| 33 given bot. These functions are bound to this element. If a column is not
listed here, a sane |
| 34 default will be used (see _column()). |
| 35 _headerMap: Object, a mapping of column name to the displayed text for a col
umn. |
| 36 _specialColumns, Array<String> A list of "special" column names, that is, co
lumns which will |
| 37 have html in them, provided by the client. non-special (i.e. plain colun
ns) just contain |
| 38 text and will have their content provided by _attribute (see below). |
| 39 _specialSort, Object, A mapping of column name to a function that implements
custom sorting |
| 40 rules. The function will be given (dir, a, b) and is expected to return
an int, as a normal |
| 41 sort comparison function would. Otherwise, natural comparison of a and b
is used |
| 42 (see _compare()). |
| 43 |
| 44 A client must define the following methods: |
| 45 _attribute(i, col, default): Given the item i, return an array of values for
the column "col", |
| 46 or an array containting just the default, if not. This is only used as a
default when a |
| 47 column does not appear in _columnMap. |
| 48 |
| 49 This behavior provides the following properties: |
| 50 _filteredSortedItems, Array<Object>, The list of items that should shown, af
ter filtering and |
| 51 sorting. |
| 52 _plainColumns, Array<String>, the list of columns with any special columns s
tripped out. |
| 53 |
| 54 This behavior provides the following methods: |
| 55 _column(col, item): Return the text content of item for a column. |
| 56 _header(col): Return the header for a column, defaulting to the column name. |
| 57 _hide(col): Return a boolean based on whether to hide this column. |
| 58 _sortChange(event): Update the sorting based on an event created by sort-tog
gle. |
| 59 --> |
| 60 <link rel="import" href="common-behavior.html"> |
| 61 <dom-module id="dynamic-table-style"> |
| 62 <template> |
| 63 <style> |
| 64 table { |
| 65 border-collapse: collapse; |
| 66 margin-left: 5px; |
| 67 } |
| 68 td, th { |
| 69 border: 1px solid #DDD; |
| 70 padding: 5px; |
| 71 } |
| 72 th { |
| 73 position: relative; |
| 74 } |
| 75 sort-toggle { |
| 76 position: absolute; |
| 77 right: 0; |
| 78 top: 0.4em; |
| 79 } |
| 80 </style> |
| 81 |
| 82 </template> |
| 83 </dom-module> |
| 84 |
| 85 <script> |
| 86 (function(){ |
| 87 // This behavior wraps up all the shared swarming functionality. |
| 88 SwarmingBehaviors.DynamicTableBehavior = [SwarmingBehaviors.CommonBehavior,
{ |
| 89 |
| 90 properties: { |
| 91 |
| 92 _columns: { |
| 93 type: Array, |
| 94 }, |
| 95 |
| 96 _filter: { |
| 97 type: Function, |
| 98 }, |
| 99 |
| 100 _filteredSortedItems: { |
| 101 type: Array, |
| 102 computed: "_filterAndSort(_items,_filter.*,_sort.*)" |
| 103 }, |
| 104 |
| 105 _items: { |
| 106 type: Array, |
| 107 }, |
| 108 |
| 109 _plainColumns: { |
| 110 type: Array, |
| 111 computed: "_stripSpecial(_columns.*)", |
| 112 }, |
| 113 |
| 114 // _sort is an Object {name:String, direction:String}. |
| 115 _sort: { |
| 116 type: Object, |
| 117 computed: "_makeSortObject(_sortstr)", |
| 118 }, |
| 119 |
| 120 _sortstr: { |
| 121 type: String, |
| 122 }, |
| 123 |
| 124 _verbose: { |
| 125 type: Boolean, |
| 126 } |
| 127 }, |
| 128 |
| 129 _column: function(col, key) { |
| 130 var f = this._columnMap[col]; |
| 131 if (!f) { |
| 132 f = function(key) { |
| 133 var c = this._attribute(key, col, "none"); |
| 134 if (this._verbose) { |
| 135 return c.join(" | "); |
| 136 } |
| 137 return c[0]; |
| 138 } |
| 139 } |
| 140 return f.bind(this)(key); |
| 141 }, |
| 142 |
| 143 _compare: function(a, b) { |
| 144 if (!this._sort) { |
| 145 return 0; |
| 146 } |
| 147 var dir = 1; |
| 148 if (this._sort.direction === "desc") { |
| 149 dir = -1; |
| 150 } |
| 151 var sort = this._specialSort[this._sort.name]; |
| 152 if (sort) { |
| 153 return sort.bind(this)(dir, a, b); |
| 154 } |
| 155 // Default to a natural compare of the columns. |
| 156 var aCol = this._column(this._sort.name, a); |
| 157 var bCol = this._column(this._sort.name, b); |
| 158 |
| 159 return dir * swarming.naturalCompare(aCol, bCol); |
| 160 }, |
| 161 |
| 162 _filterAndSort: function() { |
| 163 // We intentionally sort this._items (and not a copy) to allow users to |
| 164 // "chain" sorts, that is, sort by one thing and then another, and |
| 165 // have both orderings properly impact the list. |
| 166 swarming.stableSort(this._items, this._compare.bind(this)); |
| 167 var items = this._items; |
| 168 if (this._filter) { |
| 169 items = items.filter(this._filter.bind(this)); |
| 170 } |
| 171 |
| 172 return items; |
| 173 }, |
| 174 |
| 175 _header: function(col){ |
| 176 return this._headerMap[col] || col; |
| 177 }, |
| 178 |
| 179 _hide: function(col) { |
| 180 return this._columns.indexOf(col) === -1; |
| 181 }, |
| 182 |
| 183 _makeSortObject: function(sortstr){ |
| 184 if (!sortstr) { |
| 185 return undefined; |
| 186 } |
| 187 var pieces = sortstr.split(":"); |
| 188 if (pieces.length != 2) { |
| 189 // fail safe |
| 190 return {name: "id", direction: "asc"}; |
| 191 } |
| 192 return { |
| 193 name: pieces[0], |
| 194 direction: pieces[1], |
| 195 } |
| 196 }, |
| 197 |
| 198 _sortChange: function(e) { |
| 199 // The event we get from sort-toggle tells us the name of what needs |
| 200 // to be sorting and how to sort it. |
| 201 if (!(e && e.detail && e.detail.name)) { |
| 202 return; |
| 203 } |
| 204 // should trigger the computation of _sort and __filterAndSort |
| 205 this.set("_sortstr", e.detail.name + ":" + e.detail.direction); |
| 206 }, |
| 207 // _stripSpecial removes the special columns and sorts the remaining |
| 208 // columns so they always appear in the same order, regardless of |
| 209 // the order they are added. |
| 210 _stripSpecial: function(){ |
| 211 return this._columns.filter(function(c) { |
| 212 return this._specialColumns.indexOf(c) === -1; |
| 213 }.bind(this)).sort(); |
| 214 }, |
| 215 |
| 216 // Common columns shared between tasklist and botlist |
| 217 _commonColumns: function() { |
| 218 // return a fresh object so all elements have their own copy |
| 219 return { |
| 220 android_devices: function(bot) { |
| 221 var devs = this._attribute(bot, "android_devices", "0"); |
| 222 if (this._verbose) { |
| 223 return devs.join(" | ") + " devices available"; |
| 224 } |
| 225 // max() works on strings as long as they can be coerced to Number. |
| 226 return Math.max(...devs) + " devices available"; |
| 227 }, |
| 228 device_type: function(bot) { |
| 229 var dt = this._attribute(bot, "device_type", "none"); |
| 230 dt = dt[0]; |
| 231 var alias = swarming.alias.android(dt); |
| 232 if (alias === "unknown") { |
| 233 return dt; |
| 234 } |
| 235 return swarming.alias.apply(dt, alias); |
| 236 }, |
| 237 gpu: function(bot){ |
| 238 var gpus = this._attribute(bot, "gpu", "none"); |
| 239 var verbose = [] |
| 240 var named = []; |
| 241 // non-verbose mode has only the top level GPU info "e.g. NVidia" |
| 242 // which is found by looking for gpu ids w/o a colon. |
| 243 gpus.forEach(function(g){ |
| 244 var alias = swarming.alias.gpu(g); |
| 245 if (alias === "unknown") { |
| 246 verbose.push(g); |
| 247 if (g.indexOf(":") === -1) { |
| 248 named.push(g); |
| 249 } |
| 250 return; |
| 251 } |
| 252 verbose.push(swarming.alias.apply(g, alias)); |
| 253 if (g.indexOf(":") === -1) { |
| 254 named.push(swarming.alias.apply(g, alias)); |
| 255 } |
| 256 }.bind(this)) |
| 257 if (this._verbose || !named.length) { |
| 258 return verbose.join(" | "); |
| 259 } |
| 260 return named.join(" | "); |
| 261 }, |
| 262 pool: function(bot) { |
| 263 var pool = this._attribute(bot, "pool"); |
| 264 return pool.join(" | "); |
| 265 }, |
| 266 }; |
| 267 }, |
| 268 |
| 269 |
| 270 }]; |
| 271 })(); |
| 272 </script> |
| OLD | NEW |