Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <!-- | 1 <!-- |
| 2 Copyright 2016 The LUCI Authors. All rights reserved. | 2 Copyright 2016 The LUCI Authors. All rights reserved. |
| 3 Use of this source code is governed under the Apache License, Version 2.0 | 3 Use of this source code is governed under the Apache License, Version 2.0 |
| 4 that can be found in the LICENSE file. | 4 that can be found in the LICENSE file. |
| 5 | 5 |
| 6 This in an HTML Import-able file that contains the definition | 6 This in an HTML Import-able file that contains the definition |
| 7 of the following elements: | 7 of the following elements: |
| 8 | 8 |
| 9 <bot-page> | 9 <bot-page> |
| 10 | 10 |
| 11 bot-page shows the tasks, events, and dimensions of a bot. | 11 bot-page shows the tasks, events, and dimensions of a bot. |
| 12 | 12 |
| 13 This is a top-level element. | 13 This is a top-level element. |
| 14 | 14 |
| 15 Properties: | 15 Properties: |
| 16 bot_id: String, Used in testing to specify a bot_id | 16 bot_id: String, Used in testing to specify a bot_id |
| 17 client_id: String, Oauth 2.0 client id. It will be set by server-side | 17 client_id: String, Oauth 2.0 client id. It will be set by server-side |
| 18 template evaluation. | 18 template evaluation. |
| 19 | 19 |
| 20 Methods: | 20 Methods: |
| 21 None. | 21 None. |
| 22 | 22 |
| 23 Events: | 23 Events: |
| 24 None. | 24 None. |
| 25 --> | 25 --> |
| 26 | 26 |
| 27 <link rel="import" href="/res/imp/bower_components/iron-collapse/iron-collapse.h tml"> | |
| 28 <link rel="import" href="/res/imp/bower_components/iron-icon/iron-icon.html"> | |
| 29 <link rel="import" href="/res/imp/bower_components/iron-icons/iron-icons.html"> | |
| 30 <link rel="import" href="/res/imp/bower_components/paper-button/paper-button.htm l"> | |
| 31 <link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox .html"> | |
| 32 <link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html" > | |
| 33 <link rel="import" href="/res/imp/bower_components/paper-tabs/paper-tabs.html"> | |
| 34 <link rel="import" href="/res/imp/bower_components/paper-icon-button/paper-icon- button.html"> | |
| 27 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> | 35 <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> |
| 28 | 36 |
| 29 <link rel="import" href="/res/imp/common/common-behavior.html"> | |
| 30 <link rel="import" href="/res/imp/common/swarming-app.html"> | 37 <link rel="import" href="/res/imp/common/swarming-app.html"> |
| 31 <link rel="import" href="/res/imp/common/url-param.html"> | 38 <link rel="import" href="/res/imp/common/url-param.html"> |
| 32 | 39 |
| 33 <link rel="import" href="bot-page-data.html"> | 40 <link rel="import" href="bot-page-data.html"> |
| 41 <link rel="import" href="bot-page-shared-behavior.html"> | |
| 34 | 42 |
| 35 | 43 |
| 36 <dom-module id="bot-page"> | 44 <dom-module id="bot-page"> |
| 37 <template> | 45 <template> |
| 38 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style"> | 46 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app- style"> |
| 39 | 47 |
| 48 .header { | |
| 49 max-width: 450px; | |
| 50 } | |
| 51 | |
| 52 .title { | |
| 53 font-size: 1.5em; | |
| 54 font-weight: bold; | |
| 55 margin-bottom: 5px; | |
| 56 } | |
| 57 .id_input { | |
| 58 --paper-input-container-input: { | |
| 59 font-size: 2em; | |
| 60 }; | |
| 61 } | |
| 62 .refresh { | |
| 63 max-width: 65px; | |
| 64 max-height: 65px; | |
| 65 width: initial; | |
| 66 height: initial; | |
| 67 margin: 6px; | |
| 68 } | |
| 69 | |
| 70 table { | |
| 71 border-collapse: collapse; | |
| 72 margin-left: 5px; | |
| 73 margin-bottom: 5px; | |
| 74 } | |
| 75 td, th { | |
| 76 border: 1px solid #BBB; | |
| 77 padding: 5px; | |
| 78 } | |
| 79 | |
| 80 .quarantined, .failed_task { | |
| 81 background-color: #ffdddd; | |
| 82 } | |
| 83 .dead { | |
| 84 background-color: #cccccc; | |
| 85 } | |
| 86 | |
| 87 .message { | |
| 88 white-space: pre-line; | |
| 89 font-family: monospace; | |
| 90 } | |
| 91 | |
| 92 .bot_state { | |
| 93 white-space: pre; | |
| 94 font-family: monospace; | |
| 95 margin-bottom: 10px; | |
| 96 } | |
| 97 | |
| 98 .show_all { | |
| 99 margin-bottom: 5px; | |
| 100 } | |
| 101 | |
| 102 paper-tabs { | |
| 103 background-color: #1F78B4; | |
| 104 color: #fff; | |
| 105 max-width: 600px; | |
| 106 margin-bottom: 5px; | |
| 107 } | |
| 108 paper-tab.iron-selected { | |
| 109 background-color: #A6CEE3; | |
| 110 border: 2px solid #1F78B4; | |
| 111 color: #fff; | |
| 112 font-weight: bold; | |
| 113 text-decoration: underline; | |
| 114 } | |
| 115 | |
| 40 </style> | 116 </style> |
| 41 | 117 |
| 42 <url-param name="id" | 118 <url-param name="id" |
| 43 value="{{bot_id}}"> | 119 value="{{bot_id}}"> |
| 44 </url-param> | 120 </url-param> |
| 121 <url-param name="show_all_events" | |
| 122 value="{{_show_all}}"> | |
| 123 </url-param> | |
| 124 <url-param name="selected" | |
| 125 value="{{_selected}}"> | |
| 126 </url-param> | |
| 127 <url-param name="show_state" | |
| 128 value="{{_show_state}}"> | |
| 129 </url-param> | |
| 45 | 130 |
| 46 <swarming-app | 131 <swarming-app |
| 47 client_id="[[client_id]]" | 132 client_id="[[client_id]]" |
| 48 auth_headers="{{_auth_headers}}" | 133 auth_headers="{{_auth_headers}}" |
| 134 permissions="{{_permissions}}" | |
| 49 signed_in="{{_signed_in}}" | 135 signed_in="{{_signed_in}}" |
| 50 | 136 |
| 51 busy="[[_busy]]" | 137 busy="[[_busy]]" |
| 52 name="Swarming Bot Page"> | 138 name="Swarming Bot Page"> |
| 53 | 139 |
| 54 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> | 140 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> |
| 55 | 141 |
| 56 <div hidden$="[[_not(_signed_in)]]"> | 142 <div hidden$="[[_not(_signed_in)]]"> |
| 57 | 143 |
| 58 <bot-page-data | 144 <bot-page-data |
| 59 auth_headers="[[_auth_headers]]" | 145 auth_headers="[[_auth_headers]]" |
| 60 bot_id="[[bot_id]]" | 146 bot_id="[[bot_id]]" |
| 61 | 147 |
| 62 bot="{{_bot}}" | 148 bot="{{_bot}}" |
| 63 busy="{{_busy}}" | 149 busy="{{_busy}}" |
| 64 events="{{_events}}" | 150 events="{{_events}}" |
| 65 tasks="{{_tasks}}"> | 151 tasks="{{_tasks}}"> |
| 66 </bot-page-data> | 152 </bot-page-data> |
| 67 | 153 |
| 68 <h1> Bot Page Stub </h1> | 154 <div class="header horizontal layout"> |
| 155 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input> | |
| 156 <paper-icon-button class="refresh" icon="icons:refresh"></paper-icon-b utton> | |
| 157 </div> | |
| 158 | |
| 159 <div> | |
| 160 <table> | |
| 161 <tr class$="[[_isDead(_bot)]]"> | |
| 162 <td>Last Seen</td> | |
| 163 <td title="[[_bot.human_last_seen_ts]]"> | |
| 164 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> | |
| 165 <td> | |
| 166 <!-- dom-ifs are slightly less performant than hidden$=, but | |
| 167 prevent things from first drawing and then hiding. We prefer to | |
| 168 not flash buttons or quarantined messages --> | |
| 169 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> | |
| 170 <paper-button | |
| 171 raised> | |
| 172 Shut Down Gracefully | |
| 173 </paper-button> | |
| 174 </template> | |
| 175 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> | |
| 176 <paper-button | |
| 177 raised> | |
| 178 Delete Bot | |
| 179 </paper-button> | |
| 180 </template> | |
| 181 </td> | |
| 182 </tr> | |
| 183 <template is="dom-if" if="[[_bot.quarantined]]"> | |
| 184 <tr class="quarantined"> | |
| 185 <td>Quarantined</td> | |
| 186 <td colspan="2">[[_quarantineMessage(_bot)]]</td> | |
| 187 </tr> | |
| 188 </template> | |
| 189 <tr> | |
| 190 <td>Current Task</td> | |
| 191 <td> | |
| 192 <a target="_blank" href$="[[_taskLink(_bot.task_id)]]"> | |
| 193 [[_task(_bot)]] | |
| 194 </a> | |
| 195 </td> | |
| 196 <td> | |
| 197 <!-- TODO(kjlubick) add the cancel button when swarming can | |
| 198 cancel running tasks --> | |
| 199 </td> | |
| 200 </tr> | |
| 201 <tr> | |
| 202 <td rowspan$="[[_numRows(_bot.dimensions)]]">Dimensions</td> | |
| 203 </tr> | |
| 204 <template | |
| 205 is="dom-repeat" | |
| 206 items="[[_bot.dimensions]]" | |
| 207 as="dim"> | |
| 208 <tr> | |
| 209 <td>[[dim.key]]</td> | |
| 210 <td>[[_concat(dim.value)]]</td> | |
| 211 </tr> | |
| 212 </template> | |
| 213 | |
| 214 <tr> | |
| 215 <td>External IP</td> | |
| 216 <td>[[_bot.external_ip]]</td> | |
| 217 <td></td> | |
| 218 </tr> | |
| 219 <tr> | |
| 220 <td>Swarming Revision</td> | |
| 221 <td> | |
| 222 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_shorte n(_bot.version,'8')]]</a> | |
| 223 </td> | |
| 224 <td></td> | |
| 225 </tr> | |
| 226 <tr> | |
| 227 <td>First seen</td> | |
| 228 <td title="[[_bot.human_first_seen_ts]]"> | |
| 229 [[_timeDiffApprox(_bot.first_seen_ts)]] ago | |
| 230 </td> | |
| 231 <td></td> | |
| 232 </tr> | |
| 233 <tr> | |
| 234 <td>Authenticated as</td> | |
| 235 <td>[[_bot.authenticated_as]]</td> | |
| 236 <td></td> | |
| 237 </tr> | |
| 238 </table> | |
| 239 | |
| 240 <span class="title">State</span> | |
| 241 <paper-icon-button | |
| 242 hidden="[[_show_state]]" | |
| 243 icon="icons:add-circle-outline" | |
| 244 on-tap="_toggleState"> | |
| 245 </paper-icon-button> | |
| 246 <paper-icon-button | |
| 247 hidden="[[_not(_show_state)]]" | |
| 248 icon="icons:remove-circle-outline" | |
| 249 on-tap="_toggleState"> | |
| 250 </paper-icon-button> | |
| 251 | |
| 252 <iron-collapse id="collapse" opened="[[_show_state]]"> | |
| 253 <div class="bot_state">[[_prettyPrint(_bot.state)]]</div> | |
| 254 </iron-collapse> | |
| 255 </div> | |
| 256 | |
| 257 <paper-tabs selected="{{_selected}}" no-bar> | |
| 258 <paper-tab>Tasks</paper-tab> | |
| 259 <paper-tab>Events</paper-tab> | |
| 260 </paper-tabs> | |
| 261 | |
| 262 <template is="dom-if" if="[[_not(_selected)]]"> | |
| 263 <table> | |
| 264 <thead> | |
| 265 <tr> | |
| 266 <th>Task</th> | |
| 267 <th>Started</th> | |
| 268 <th>Duration</th> | |
| 269 <th>Result</th> | |
| 270 </tr> | |
| 271 </thead> | |
| 272 <tbody> | |
| 273 <template is="dom-repeat" items="{{_tasks}}" as="task"> | |
| 274 <tr> | |
| 275 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td> | |
| 276 <td>[[task.human_started_ts]]</td> | |
| 277 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td> | |
| 278 <td>[[task.state]]</td> | |
| 279 </tr> | |
| 280 </template> | |
| 281 </tbody> | |
| 282 </table> | |
| 283 </template> | |
| 284 | |
| 285 <template is="dom-if" if="[[_selected]]"> | |
| 286 <div class="tab_content"> | |
| 287 <paper-checkbox class="show_all" checked="{{_show_all}}"> | |
| 288 Show all events | |
| 289 </paper-checkbox> | |
| 290 <table class="events_table"> | |
| 291 <thead> | |
| 292 <tr> | |
| 293 <th>Message</th> | |
| 294 <th>Type</th> | |
| 295 <th>Timestamp</th> | |
| 296 <th>Task ID</th> | |
| 297 <th>Version</th> | |
| 298 </tr> | |
| 299 </thead> | |
| 300 <tbody> | |
| 301 <template is="dom-repeat" items="{{_eventList(_events,_show_all) }}" as="event"> | |
| 302 <tr> | |
| 303 <td class="message">[[event.message]]</a></td> | |
| 304 <td>[[event.event_type]]</td> | |
| 305 <td>[[event.human_ts]]</td> | |
| 306 <td><a target="_blank" href$="[[_taskLink(event.task_id)]]"> [[event.task_id]]</a></td> | |
| 307 <td> | |
| 308 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_ shorten(_bot.version,'8')]]</a> | |
| 309 </td> | |
| 310 </tr> | |
| 311 </template> | |
| 312 </tbody> | |
| 313 </table> | |
| 314 </div> | |
| 315 </template> | |
| 316 </div> | |
| 69 </div> | 317 </div> |
| 70 | 318 |
| 71 </swarming-app> | 319 </swarming-app> |
| 72 | 320 |
| 73 </template> | 321 </template> |
| 74 <script> | 322 <script> |
| 75 (function(){ | 323 (function(){ |
| 76 | 324 |
| 77 | 325 |
| 78 Polymer({ | 326 Polymer({ |
| 79 is: 'bot-page', | 327 is: 'bot-page', |
| 80 | 328 |
| 81 behaviors: [ | 329 behaviors: [ |
| 82 SwarmingBehaviors.CommonBehavior, | 330 SwarmingBehaviors.BotPageBehavior, |
| 83 ], | 331 ], |
| 84 | 332 |
| 85 properties: { | 333 properties: { |
| 86 bot_id: { | 334 bot_id: { |
| 87 type: String, | 335 type: String, |
| 88 }, | 336 }, |
| 89 client_id: { | 337 client_id: { |
| 90 type: String, | 338 type: String, |
| 91 }, | 339 }, |
| 92 | 340 |
| 341 // private | |
|
stephana
2016/09/01 15:16:18
nit: not necessary.
kjlubick
2016/09/01 17:24:08
Removed.
| |
| 342 _bot: { | |
| 343 type: Object, | |
| 344 }, | |
| 345 _selected: { | |
| 346 type: Number, | |
| 347 }, | |
| 348 _show_all: { | |
| 349 type: Boolean, | |
| 350 }, | |
| 351 _show_state: { | |
| 352 type: Boolean, | |
| 353 } | |
| 93 }, | 354 }, |
| 94 | 355 |
| 356 _canCancel: function(bot, permissions) { | |
| 357 return bot && bot.task_id && permissions.cancel_task; | |
| 358 }, | |
| 359 | |
| 360 _canDelete: function(bot, permissions) { | |
| 361 return bot && bot.is_dead && permissions.delete_bot; | |
| 362 }, | |
| 363 | |
| 364 _canShutdown: function(bot, permissions){ | |
| 365 return bot && !bot.is_dead && permissions.terminate_bot; | |
| 366 }, | |
| 367 | |
| 368 _concat: function(arr) { | |
| 369 if (!arr) { | |
| 370 return ""; | |
| 371 } | |
| 372 return arr.join(" | "); | |
| 373 }, | |
| 374 | |
| 375 _eventList(events, showAll) { | |
| 376 if (!events) { | |
| 377 return []; | |
| 378 } | |
| 379 return events.filter(function(e){ | |
| 380 return showAll || e.message; | |
| 381 }); | |
| 382 }, | |
| 383 | |
| 384 _isDead(bot){ | |
| 385 if (bot && bot.is_dead) { | |
| 386 return "dead"; | |
| 387 } | |
| 388 return ""; | |
| 389 }, | |
| 390 | |
| 391 _luciLink: function(revision) { | |
| 392 if (!revision) { | |
| 393 return undefined; | |
| 394 } | |
| 395 return "https://github.com/luci/luci-py/commit/" + revision; | |
| 396 | |
| 397 }, | |
| 398 | |
| 399 _numRows: function(arr) { | |
| 400 if (!arr || !arr.length) { | |
| 401 return 1; | |
| 402 } | |
| 403 return 1 + arr.length; | |
| 404 }, | |
| 405 | |
| 406 _prettyPrint: function(obj) { | |
| 407 obj = obj || {}; | |
| 408 return JSON.stringify(obj, null, 2); | |
| 409 }, | |
| 410 | |
| 411 _quarantineMessage: function(bot) { | |
| 412 if (bot && bot.quarantined) { | |
| 413 var msg = bot.state.quarantined; | |
| 414 // Sometimes, the quarantined message is actually in "error". This | |
| 415 // happens when the bot code has thrown an exception. | |
| 416 if (msg === undefined || msg === "true" || msg === true) { | |
| 417 msg = this._attribute(bot, "error"); | |
| 418 } | |
| 419 return msg || "True"; | |
| 420 } | |
| 421 return ""; | |
| 422 }, | |
| 423 | |
| 424 _shorten: function(str, length) { | |
| 425 if (!str || ! length) { | |
| 426 return ""; | |
| 427 } | |
| 428 return str.substring(0, length); | |
| 429 }, | |
| 430 | |
| 431 _task: function(bot) { | |
| 432 return (bot && bot.task_id) || "idle"; | |
| 433 }, | |
| 434 | |
| 435 _taskLink: function(task_id) { | |
| 436 // TODO(kjlubick): Migrate this to /newui/ when ready | |
| 437 if (task_id) { | |
| 438 return "/user/task/" + task_id; | |
| 439 } | |
| 440 return undefined; | |
| 441 }, | |
| 442 | |
| 443 _toggleState: function() { | |
| 444 this.set("_show_state", !this._show_state); | |
| 445 } | |
| 446 | |
| 95 }); | 447 }); |
| 96 })(); | 448 })(); |
| 97 </script> | 449 </script> |
| 98 </dom-module> | 450 </dom-module> |
| OLD | NEW |