| OLD | NEW |
| 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 14592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14603 }, | 14603 }, |
| 14604 auth_headers: { | 14604 auth_headers: { |
| 14605 type: Object, | 14605 type: Object, |
| 14606 notify: true, | 14606 notify: true, |
| 14607 }, | 14607 }, |
| 14608 signed_in: { | 14608 signed_in: { |
| 14609 type: Boolean, | 14609 type: Boolean, |
| 14610 value: false, | 14610 value: false, |
| 14611 notify:true, | 14611 notify:true, |
| 14612 }, | 14612 }, |
| 14613 permissions: { |
| 14614 type: Object, |
| 14615 value: function() { |
| 14616 // TODO(kjlubick): Make this call the whoami endpoint after signing
in. |
| 14617 return { |
| 14618 can_cancel_task: true, |
| 14619 } |
| 14620 }, |
| 14621 notify: true, |
| 14622 }, |
| 14613 | 14623 |
| 14614 busy: { | 14624 busy: { |
| 14615 type: Boolean, | 14625 type: Boolean, |
| 14616 }, | 14626 }, |
| 14617 name: { | 14627 name: { |
| 14618 type: String, | 14628 type: String, |
| 14619 }, | 14629 }, |
| 14620 }, | 14630 }, |
| 14621 | 14631 |
| 14622 }); | 14632 }); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14676 }, | 14686 }, |
| 14677 | 14687 |
| 14678 }); | 14688 }); |
| 14679 </script> | 14689 </script> |
| 14680 </dom-module><script> | 14690 </dom-module><script> |
| 14681 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; | 14691 window.SwarmingBehaviors = window.SwarmingBehaviors || {}; |
| 14682 (function(){ | 14692 (function(){ |
| 14683 // This behavior wraps up all the shared swarming functionality. | 14693 // This behavior wraps up all the shared swarming functionality. |
| 14684 SwarmingBehaviors.CommonBehavior = { | 14694 SwarmingBehaviors.CommonBehavior = { |
| 14685 | 14695 |
| 14696 // _getJsonAsync makes an XHR to a url, parses the response as JSON |
| 14697 // and sticks the resulting object into the property with the name given |
| 14698 // by "bindTo". If busy is defined, the property with that name will be |
| 14699 // set to true while the request is in flight and false afterwards. |
| 14700 // request headers (e.g. authentication) and query params will be used if |
| 14701 // provided. On error, bindTo will be set to false. It is not set to |
| 14702 // undefined because computed values in Polymer don't fire if a property |
| 14703 // is undefined. Clients should check that bindTo is not falsey. |
| 14704 _getJsonAsync: function(bindTo, url, busy, headers, params) { |
| 14705 if (!bindTo || !url) { |
| 14706 console.log("Need at least a polymer element to bind to and a url"); |
| 14707 return; |
| 14708 } |
| 14709 if (busy) { |
| 14710 this.set(busy, true); |
| 14711 } |
| 14712 url = url + "?" + sk.query.fromParamSet(params); |
| 14713 sk.request("GET", url, "", headers).then(JSON.parse).then(function(json)
{ |
| 14714 this.set(bindTo, json); |
| 14715 if (busy) { |
| 14716 this.set(busy, false); |
| 14717 } |
| 14718 }.bind(this)).catch(function(reason){ |
| 14719 console.log("Reason for failure of request to " + url, reason); |
| 14720 this.set(bindTo, false); |
| 14721 if (busy) { |
| 14722 this.set(busy, false); |
| 14723 } |
| 14724 }.bind(this)); |
| 14725 }, |
| 14726 |
| 14686 _not: function(a) { | 14727 _not: function(a) { |
| 14687 return !a; | 14728 return !a; |
| 14688 }, | 14729 }, |
| 14689 | 14730 |
| 14690 _or: function() { | 14731 _or: function() { |
| 14691 var result = false; | 14732 var result = false; |
| 14692 // can't use .foreach, as arguments isn't really an Array. | 14733 // can't use .foreach, as arguments isn't really an Array. |
| 14693 for (var i = 0; i < arguments.length; i++) { | 14734 for (var i = 0; i < arguments.length; i++) { |
| 14694 result = result || arguments[i]; | 14735 result = result || arguments[i]; |
| 14695 } | 14736 } |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14850 _stripSpecial: function(){ | 14891 _stripSpecial: function(){ |
| 14851 return this._columns.filter(function(c) { | 14892 return this._columns.filter(function(c) { |
| 14852 return this._specialColumns.indexOf(c) === -1; | 14893 return this._specialColumns.indexOf(c) === -1; |
| 14853 }.bind(this)).sort(); | 14894 }.bind(this)).sort(); |
| 14854 }, | 14895 }, |
| 14855 | 14896 |
| 14856 // Common columns shared between tasklist and botlist | 14897 // Common columns shared between tasklist and botlist |
| 14857 _commonColumns: function() { | 14898 _commonColumns: function() { |
| 14858 // return a fresh object so all elements have their own copy | 14899 // return a fresh object so all elements have their own copy |
| 14859 return { | 14900 return { |
| 14860 android_devices: function(bot) { | |
| 14861 var devs = this._attribute(bot, "android_devices", "0"); | |
| 14862 if (this._verbose) { | |
| 14863 return devs.join(" | ") + " devices available"; | |
| 14864 } | |
| 14865 // max() works on strings as long as they can be coerced to Number. | |
| 14866 return Math.max(...devs) + " devices available"; | |
| 14867 }, | |
| 14868 device_type: function(bot) { | 14901 device_type: function(bot) { |
| 14869 var dt = this._attribute(bot, "device_type", "none"); | 14902 var dt = this._attribute(bot, "device_type", "none"); |
| 14870 dt = dt[0]; | 14903 dt = dt[0]; |
| 14871 var alias = swarming.alias.android(dt); | 14904 var alias = swarming.alias.android(dt); |
| 14872 if (alias === "unknown") { | 14905 if (alias === "unknown") { |
| 14873 return dt; | 14906 return dt; |
| 14874 } | 14907 } |
| 14875 return swarming.alias.apply(dt, alias); | 14908 return swarming.alias.apply(dt, alias); |
| 14876 }, | 14909 }, |
| 14877 gpu: function(bot){ | 14910 gpu: function(bot){ |
| (...skipping 9248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 24126 "device_type": "Device Type", | 24159 "device_type": "Device Type", |
| 24127 "disk_space": "Free Space (MB)", | 24160 "disk_space": "Free Space (MB)", |
| 24128 "gpu": "GPU", | 24161 "gpu": "GPU", |
| 24129 "os": "OS", | 24162 "os": "OS", |
| 24130 "pool": "Pool", | 24163 "pool": "Pool", |
| 24131 "status": "Status", | 24164 "status": "Status", |
| 24132 "xcode_version": "XCode Version", | 24165 "xcode_version": "XCode Version", |
| 24133 }; | 24166 }; |
| 24134 | 24167 |
| 24135 var columnMap = { | 24168 var columnMap = { |
| 24169 android_devices: function(bot) { |
| 24170 var devs = this._attribute(bot, "android_devices", "0"); |
| 24171 if (this._verbose) { |
| 24172 return devs.join(" | ") + " devices available"; |
| 24173 } |
| 24174 // max() works on strings as long as they can be coerced to Number. |
| 24175 return Math.max(...devs) + " devices available"; |
| 24176 }, |
| 24136 disk_space: function(bot) { | 24177 disk_space: function(bot) { |
| 24137 var aliased = []; | 24178 var aliased = []; |
| 24138 bot.disks.forEach(function(disk){ | 24179 bot.disks.forEach(function(disk){ |
| 24139 var alias = sk.human.bytes(disk.mb, swarming.MB); | 24180 var alias = sk.human.bytes(disk.mb, swarming.MB); |
| 24140 aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias)); | 24181 aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias)); |
| 24141 }.bind(this)); | 24182 }.bind(this)); |
| 24142 if (this._verbose) { | 24183 if (this._verbose) { |
| 24143 return aliased.join(" | "); | 24184 return aliased.join(" | "); |
| 24144 } | 24185 } |
| 24145 return aliased[0]; | 24186 return aliased[0]; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 24291 _taskLink: function(data) { | 24332 _taskLink: function(data) { |
| 24292 if (data && data.task_id) { | 24333 if (data && data.task_id) { |
| 24293 return "/user/task/" + data.task_id; | 24334 return "/user/task/" + data.task_id; |
| 24294 } | 24335 } |
| 24295 return undefined; | 24336 return undefined; |
| 24296 } | 24337 } |
| 24297 | 24338 |
| 24298 }); | 24339 }); |
| 24299 })(); | 24340 })(); |
| 24300 </script> | 24341 </script> |
| 24301 </dom-module><dom-module id="task-filters" assetpath="/res/imp/tasklist/"> | 24342 </dom-module><script> |
| 24343 /** @polymerBehavior Polymer.PaperButtonBehavior */ |
| 24344 Polymer.PaperButtonBehaviorImpl = { |
| 24345 properties: { |
| 24346 /** |
| 24347 * The z-depth of this element, from 0-5. Setting to 0 will remove the |
| 24348 * shadow, and each increasing number greater than 0 will be "deeper" |
| 24349 * than the last. |
| 24350 * |
| 24351 * @attribute elevation |
| 24352 * @type number |
| 24353 * @default 1 |
| 24354 */ |
| 24355 elevation: { |
| 24356 type: Number, |
| 24357 reflectToAttribute: true, |
| 24358 readOnly: true |
| 24359 } |
| 24360 }, |
| 24361 |
| 24362 observers: [ |
| 24363 '_calculateElevation(focused, disabled, active, pressed, receivedFocusFrom
Keyboard)', |
| 24364 '_computeKeyboardClass(receivedFocusFromKeyboard)' |
| 24365 ], |
| 24366 |
| 24367 hostAttributes: { |
| 24368 role: 'button', |
| 24369 tabindex: '0', |
| 24370 animated: true |
| 24371 }, |
| 24372 |
| 24373 _calculateElevation: function() { |
| 24374 var e = 1; |
| 24375 if (this.disabled) { |
| 24376 e = 0; |
| 24377 } else if (this.active || this.pressed) { |
| 24378 e = 4; |
| 24379 } else if (this.receivedFocusFromKeyboard) { |
| 24380 e = 3; |
| 24381 } |
| 24382 this._setElevation(e); |
| 24383 }, |
| 24384 |
| 24385 _computeKeyboardClass: function(receivedFocusFromKeyboard) { |
| 24386 this.toggleClass('keyboard-focus', receivedFocusFromKeyboard); |
| 24387 }, |
| 24388 |
| 24389 /** |
| 24390 * In addition to `IronButtonState` behavior, when space key goes down, |
| 24391 * create a ripple down effect. |
| 24392 * |
| 24393 * @param {!KeyboardEvent} event . |
| 24394 */ |
| 24395 _spaceKeyDownHandler: function(event) { |
| 24396 Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event); |
| 24397 // Ensure that there is at most one ripple when the space key is held down
. |
| 24398 if (this.hasRipple() && this.getRipple().ripples.length < 1) { |
| 24399 this._ripple.uiDownAction(); |
| 24400 } |
| 24401 }, |
| 24402 |
| 24403 /** |
| 24404 * In addition to `IronButtonState` behavior, when space key goes up, |
| 24405 * create a ripple up effect. |
| 24406 * |
| 24407 * @param {!KeyboardEvent} event . |
| 24408 */ |
| 24409 _spaceKeyUpHandler: function(event) { |
| 24410 Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event); |
| 24411 if (this.hasRipple()) { |
| 24412 this._ripple.uiUpAction(); |
| 24413 } |
| 24414 } |
| 24415 }; |
| 24416 |
| 24417 /** @polymerBehavior */ |
| 24418 Polymer.PaperButtonBehavior = [ |
| 24419 Polymer.IronButtonState, |
| 24420 Polymer.IronControlState, |
| 24421 Polymer.PaperRippleBehavior, |
| 24422 Polymer.PaperButtonBehaviorImpl |
| 24423 ]; |
| 24424 </script> |
| 24425 <style is="custom-style"> |
| 24426 |
| 24427 :root { |
| 24428 |
| 24429 --shadow-transition: { |
| 24430 transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1); |
| 24431 }; |
| 24432 |
| 24433 --shadow-none: { |
| 24434 box-shadow: none; |
| 24435 }; |
| 24436 |
| 24437 /* from http://codepen.io/shyndman/pen/c5394ddf2e8b2a5c9185904b57421cdb */ |
| 24438 |
| 24439 --shadow-elevation-2dp: { |
| 24440 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), |
| 24441 0 1px 5px 0 rgba(0, 0, 0, 0.12), |
| 24442 0 3px 1px -2px rgba(0, 0, 0, 0.2); |
| 24443 }; |
| 24444 |
| 24445 --shadow-elevation-3dp: { |
| 24446 box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14), |
| 24447 0 1px 8px 0 rgba(0, 0, 0, 0.12), |
| 24448 0 3px 3px -2px rgba(0, 0, 0, 0.4); |
| 24449 }; |
| 24450 |
| 24451 --shadow-elevation-4dp: { |
| 24452 box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), |
| 24453 0 1px 10px 0 rgba(0, 0, 0, 0.12), |
| 24454 0 2px 4px -1px rgba(0, 0, 0, 0.4); |
| 24455 }; |
| 24456 |
| 24457 --shadow-elevation-6dp: { |
| 24458 box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), |
| 24459 0 1px 18px 0 rgba(0, 0, 0, 0.12), |
| 24460 0 3px 5px -1px rgba(0, 0, 0, 0.4); |
| 24461 }; |
| 24462 |
| 24463 --shadow-elevation-8dp: { |
| 24464 box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), |
| 24465 0 3px 14px 2px rgba(0, 0, 0, 0.12), |
| 24466 0 5px 5px -3px rgba(0, 0, 0, 0.4); |
| 24467 }; |
| 24468 |
| 24469 --shadow-elevation-12dp: { |
| 24470 box-shadow: 0 12px 16px 1px rgba(0, 0, 0, 0.14), |
| 24471 0 4px 22px 3px rgba(0, 0, 0, 0.12), |
| 24472 0 6px 7px -4px rgba(0, 0, 0, 0.4); |
| 24473 }; |
| 24474 |
| 24475 --shadow-elevation-16dp: { |
| 24476 box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), |
| 24477 0 6px 30px 5px rgba(0, 0, 0, 0.12), |
| 24478 0 8px 10px -5px rgba(0, 0, 0, 0.4); |
| 24479 }; |
| 24480 |
| 24481 } |
| 24482 |
| 24483 </style> |
| 24484 <dom-module id="paper-material-shared-styles" assetpath="/res/imp/bower_componen
ts/paper-material/"> |
| 24302 <template> | 24485 <template> |
| 24303 <style> | 24486 <style> |
| 24304 :host { | 24487 :host { |
| 24305 display: block; | 24488 display: block; |
| 24489 position: relative; |
| 24490 } |
| 24491 |
| 24492 :host([elevation="1"]) { |
| 24493 @apply(--shadow-elevation-2dp); |
| 24494 } |
| 24495 |
| 24496 :host([elevation="2"]) { |
| 24497 @apply(--shadow-elevation-4dp); |
| 24498 } |
| 24499 |
| 24500 :host([elevation="3"]) { |
| 24501 @apply(--shadow-elevation-6dp); |
| 24502 } |
| 24503 |
| 24504 :host([elevation="4"]) { |
| 24505 @apply(--shadow-elevation-8dp); |
| 24506 } |
| 24507 |
| 24508 :host([elevation="5"]) { |
| 24509 @apply(--shadow-elevation-16dp); |
| 24306 } | 24510 } |
| 24307 </style> | 24511 </style> |
| 24512 </template> |
| 24513 </dom-module> |
| 24514 |
| 24515 |
| 24516 <dom-module id="paper-material" assetpath="/res/imp/bower_components/paper-mater
ial/"> |
| 24517 <template> |
| 24518 <style include="paper-material-shared-styles"></style> |
| 24519 <style> |
| 24520 :host([animated]) { |
| 24521 @apply(--shadow-transition); |
| 24522 } |
| 24523 </style> |
| 24524 |
| 24525 <content></content> |
| 24526 </template> |
| 24527 </dom-module> |
| 24528 <script> |
| 24529 Polymer({ |
| 24530 is: 'paper-material', |
| 24531 |
| 24532 properties: { |
| 24533 /** |
| 24534 * The z-depth of this element, from 0-5. Setting to 0 will remove the |
| 24535 * shadow, and each increasing number greater than 0 will be "deeper" |
| 24536 * than the last. |
| 24537 * |
| 24538 * @attribute elevation |
| 24539 * @type number |
| 24540 * @default 1 |
| 24541 */ |
| 24542 elevation: { |
| 24543 type: Number, |
| 24544 reflectToAttribute: true, |
| 24545 value: 1 |
| 24546 }, |
| 24547 |
| 24548 /** |
| 24549 * Set this to true to animate the shadow when setting a new |
| 24550 * `elevation` value. |
| 24551 * |
| 24552 * @attribute animated |
| 24553 * @type boolean |
| 24554 * @default false |
| 24555 */ |
| 24556 animated: { |
| 24557 type: Boolean, |
| 24558 reflectToAttribute: true, |
| 24559 value: false |
| 24560 } |
| 24561 } |
| 24562 }); |
| 24563 </script> |
| 24564 |
| 24565 |
| 24566 <dom-module id="paper-button" assetpath="/res/imp/bower_components/paper-button/
"> |
| 24567 <template strip-whitespace=""> |
| 24568 <style include="paper-material"> |
| 24569 :host { |
| 24570 @apply(--layout-inline); |
| 24571 @apply(--layout-center-center); |
| 24572 position: relative; |
| 24573 box-sizing: border-box; |
| 24574 min-width: 5.14em; |
| 24575 margin: 0 0.29em; |
| 24576 background: transparent; |
| 24577 -webkit-tap-highlight-color: rgba(0, 0, 0, 0); |
| 24578 -webkit-tap-highlight-color: transparent; |
| 24579 font: inherit; |
| 24580 text-transform: uppercase; |
| 24581 outline-width: 0; |
| 24582 border-radius: 3px; |
| 24583 -moz-user-select: none; |
| 24584 -ms-user-select: none; |
| 24585 -webkit-user-select: none; |
| 24586 user-select: none; |
| 24587 cursor: pointer; |
| 24588 z-index: 0; |
| 24589 padding: 0.7em 0.57em; |
| 24590 |
| 24591 @apply(--paper-font-common-base); |
| 24592 @apply(--paper-button); |
| 24593 } |
| 24594 |
| 24595 :host([raised].keyboard-focus) { |
| 24596 font-weight: bold; |
| 24597 @apply(--paper-button-raised-keyboard-focus); |
| 24598 } |
| 24599 |
| 24600 :host(:not([raised]).keyboard-focus) { |
| 24601 font-weight: bold; |
| 24602 @apply(--paper-button-flat-keyboard-focus); |
| 24603 } |
| 24604 |
| 24605 :host([disabled]) { |
| 24606 background: #eaeaea; |
| 24607 color: #a8a8a8; |
| 24608 cursor: auto; |
| 24609 pointer-events: none; |
| 24610 |
| 24611 @apply(--paper-button-disabled); |
| 24612 } |
| 24613 |
| 24614 paper-ripple { |
| 24615 color: var(--paper-button-ink-color); |
| 24616 } |
| 24617 </style> |
| 24618 |
| 24619 <content></content> |
| 24620 </template> |
| 24621 |
| 24622 <script> |
| 24623 Polymer({ |
| 24624 is: 'paper-button', |
| 24625 |
| 24626 behaviors: [ |
| 24627 Polymer.PaperButtonBehavior |
| 24628 ], |
| 24629 |
| 24630 properties: { |
| 24631 /** |
| 24632 * If true, the button should be styled with a shadow. |
| 24633 */ |
| 24634 raised: { |
| 24635 type: Boolean, |
| 24636 reflectToAttribute: true, |
| 24637 value: false, |
| 24638 observer: '_calculateElevation' |
| 24639 } |
| 24640 }, |
| 24641 |
| 24642 _calculateElevation: function() { |
| 24643 if (!this.raised) { |
| 24644 this._setElevation(0); |
| 24645 } else { |
| 24646 Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this); |
| 24647 } |
| 24648 } |
| 24649 |
| 24650 /** |
| 24651 Fired when the animation finishes. |
| 24652 This is useful if you want to wait until |
| 24653 the ripple animation finishes to perform some action. |
| 24654 |
| 24655 @event transitionend |
| 24656 Event param: {{node: Object}} detail Contains the animated node. |
| 24657 */ |
| 24658 }); |
| 24659 </script> |
| 24660 </dom-module> |
| 24661 <dom-module id="task-filters" assetpath="/res/imp/tasklist/"> |
| 24662 <template> |
| 24663 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio
ning query-column-filter-style"> |
| 24664 |
| 24665 </style> |
| 24666 |
| 24667 <url-param name="filters" value="{{_filters}}" default_values="[]" multi=""> |
| 24668 </url-param> |
| 24669 <url-param name="columns" value="{{columns}}" default_values="["name&qu
ot;,"state","created_ts","user"]" multi=""> |
| 24670 </url-param> |
| 24671 <url-param name="query" value="{{_query}}" default_value=""> |
| 24672 </url-param> |
| 24673 <url-param name="limit" default_value="200" value="{{limit}}"> |
| 24674 </url-param> |
| 24675 |
| 24676 <div class="container horizontal layout"> |
| 24677 |
| 24678 |
| 24679 <div class="narrow-down-selector"> |
| 24680 <div> |
| 24681 <paper-input id="filter" label="Search columns and filters" placeholde
r="gpu nvidia" value="{{_query}}"> |
| 24682 </paper-input> |
| 24683 </div> |
| 24684 |
| 24685 <div class="selector side-by-side" title="This shows all task tags and o
ther interesting task properties. Mark the check box to add as a column. Select
the row to see filter options."> |
| 24686 <iron-selector attr-for-selected="label" selected="{{_primarySelected}
}"> |
| 24687 <template is="dom-repeat" items="[[_primaryItems]]" as="item"> |
| 24688 <div class="selectable item horizontal layout" label="[[item]]"> |
| 24689 |
| 24690 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(ite
m,_query)]]</span>[[_afterBold(item,_query)]]</span> |
| 24691 <span class="flex"></span> |
| 24692 <paper-checkbox noink="" disabled$="[[_cantToggleColumn(item)]]"
checked="[[_columnState(item,columns.*)]]" on-change="_toggleColumn"> |
| 24693 </paper-checkbox> |
| 24694 </div> |
| 24695 </template> |
| 24696 </iron-selector> |
| 24697 </div> |
| 24698 |
| 24699 <div class="selector side-by-side" title="These are all options (if any)
that the task list can be filtered on."> |
| 24700 <template is="dom-repeat" id="secondaryList" items="[[_secondaryItems]
]" as="item"> |
| 24701 <div class="item horizontal layout" label="[[item]]"> |
| 24702 |
| 24703 <span>[[_beforeBold(item,_query)]]<span class="bold">[[_bold(item,
_query)]]</span>[[_afterBold(item,_query)]]</span> |
| 24704 <span class="flex"></span> |
| 24705 <iron-icon class="icons" icon="icons:arrow-forward" hidden="[[_can
tAddFilter(_primarySelected,item,_filters.*)]]" on-tap="_addFilter"> |
| 24706 </iron-icon> |
| 24707 </div> |
| 24708 </template> |
| 24709 </div> |
| 24710 |
| 24711 <div class="selector side-by-side" title="These tag filters are AND'd to
gether and applied to all tasks."> |
| 24712 <template is="dom-repeat" items="[[_filters]]" as="fil"> |
| 24713 <div class="item horizontal layout" label="[[fil]]"> |
| 24714 <span>[[fil]]</span> |
| 24715 <span class="flex"></span> |
| 24716 <iron-icon class="icons" icon="icons:remove-circle-outline" hidden
="[[_cantRemoveFilter(fil,_filters.*)]]" on-tap="_removeFilter"> |
| 24717 </iron-icon> |
| 24718 </div> |
| 24719 </template> |
| 24720 </div> |
| 24721 |
| 24722 <div class="side-by-side"> |
| 24723 <paper-input id="limit" label="Limit Results" auto-validate="" min="0"
max="1000" pattern="[0-9]+" value="{{limit}}"> |
| 24724 </paper-input> |
| 24725 </div> |
| 24726 </div> |
| 24727 |
| 24728 </div> |
| 24308 | 24729 |
| 24309 </template> | 24730 </template> |
| 24310 <script> | 24731 <script> |
| 24311 (function(){ | 24732 (function(){ |
| 24733 // see query-column-filter for more documentation on these properties. |
| 24734 var filterMap = { |
| 24735 state: function(task, s) { |
| 24736 var state = this._attribute(task, "state")[0]; |
| 24737 if (s === state) { |
| 24738 return true; |
| 24739 } |
| 24740 if (s === "PENDING_RUNNING") { |
| 24741 return state === "PENDING" || state === "RUNNING"; |
| 24742 } |
| 24743 var failure = this._attribute(task, "failure", false)[0]; |
| 24744 if (s === "COMPLETED_SUCCESS") { |
| 24745 return state === "COMPLETED" && !failure; |
| 24746 } |
| 24747 if (s === "COMPLETED_FAILURE") { |
| 24748 return state === "COMPLETED" && failure; |
| 24749 } |
| 24750 var tryNum = this._attribute(task, "try_number", "-1")[0]; |
| 24751 if (s === "DEDUPED") { |
| 24752 return state === "COMPLETED" && tryNum === "0"; |
| 24753 } |
| 24754 |
| 24755 }, |
| 24756 |
| 24757 }; |
| 24312 Polymer({ | 24758 Polymer({ |
| 24313 is: 'task-filters', | 24759 is: 'task-filters', |
| 24314 | 24760 |
| 24761 behaviors: [SwarmingBehaviors.QueryColumnFilter], |
| 24762 |
| 24315 properties: { | 24763 properties: { |
| 24316 // output | 24764 // output |
| 24317 columns: { | 24765 columns: { |
| 24318 type: Array, | 24766 type: Array, |
| 24319 value: function() { | |
| 24320 return ["name", "state", "user"]; | |
| 24321 }, | |
| 24322 notify: true, | |
| 24323 }, | |
| 24324 filter: { | |
| 24325 type: Function, | |
| 24326 value: function() { | |
| 24327 return function(){ | |
| 24328 return true; | |
| 24329 }; | |
| 24330 }, | |
| 24331 notify: true, | 24767 notify: true, |
| 24332 }, | 24768 }, |
| 24333 query_params: { | 24769 query_params: { |
| 24334 type: Object, | 24770 type: Object, |
| 24771 computed: "_extractQueryParams(_filters.*, limit)", |
| 24335 notify: true, | 24772 notify: true, |
| 24336 }, | 24773 }, |
| 24337 verbose: { | 24774 |
| 24338 type: Boolean, | 24775 // for QueryColumnFilter |
| 24339 value: true, | 24776 _filterMap: { |
| 24340 notify: true, | 24777 type: Object, |
| 24341 }, | 24778 value: function() { |
| 24342 } | 24779 var base = this._commonFilters(); |
| 24780 for (var attr in filterMap) { |
| 24781 base[attr] = filterMap[attr]; |
| 24782 } |
| 24783 return base; |
| 24784 }, |
| 24785 } |
| 24786 }, |
| 24787 |
| 24788 _cantToggleColumn: function(col) { |
| 24789 // Don't allow the name column to be removed, as the task list is |
| 24790 // basically meaningless without it. |
| 24791 return !col || col === "name" ; |
| 24792 }, |
| 24793 |
| 24794 _extractQueryParams: function() { |
| 24795 var params = {}; |
| 24796 var tags = []; |
| 24797 this._filters.forEach(function(f) { |
| 24798 var split = f.split(this.FILTER_SEP, 1) |
| 24799 var col = split[0]; |
| 24800 var rest = f.substring(col.length + this.FILTER_SEP.length); |
| 24801 if (col === "state") { |
| 24802 params["state"] = [rest]; |
| 24803 } else { |
| 24804 tags.push(col + this.FILTER_SEP + swarming.alias.unapply(rest)) |
| 24805 } |
| 24806 }.bind(this)); |
| 24807 params["tags"] = tags; |
| 24808 var lim = Math.floor(this.limit) |
| 24809 if (Number.isInteger(lim)) { |
| 24810 // Clamp the limit |
| 24811 lim = Math.max(lim, 1); |
| 24812 lim = Math.min(1000, lim); |
| 24813 params["limit"] = [lim]; |
| 24814 // not !== because limit could be the string "900" |
| 24815 if (this.limit != lim) { |
| 24816 this.set("limit", lim); |
| 24817 } |
| 24818 } |
| 24819 return params; |
| 24820 } |
| 24821 |
| 24343 }); | 24822 }); |
| 24344 })(); | 24823 })(); |
| 24345 </script> | 24824 </script> |
| 24346 </dom-module><dom-module id="task-list-data" assetpath="/res/imp/tasklist/"> | 24825 </dom-module><dom-module id="task-list-data" assetpath="/res/imp/tasklist/"> |
| 24347 <template> | |
| 24348 <iron-ajax id="tasklist" url="/_ah/api/swarming/v1/tasks/list" headers="[[au
th_headers]]" params="[[query_params]]" handle-as="json" last-response="{{_list}
}" loading="{{_busy1}}"> | |
| 24349 </iron-ajax> | |
| 24350 | |
| 24351 | |
| 24352 </template> | |
| 24353 <script> | 24826 <script> |
| 24354 (function(){ | 24827 (function(){ |
| 24355 Polymer({ | 24828 Polymer({ |
| 24356 is: 'task-list-data', | 24829 is: 'task-list-data', |
| 24357 | 24830 |
| 24358 behaviors: [SwarmingBehaviors.CommonBehavior], | 24831 behaviors: [ |
| 24832 SwarmingBehaviors.CommonBehavior, |
| 24833 ], |
| 24359 | 24834 |
| 24360 properties: { | 24835 properties: { |
| 24361 // inputs | 24836 // inputs |
| 24362 auth_headers: { | 24837 auth_headers: { |
| 24363 type: Object, | 24838 type: Object, |
| 24364 observer: "signIn", | 24839 observer: "signIn", |
| 24365 }, | 24840 }, |
| 24366 query_params: { | 24841 query_params: { |
| 24367 type: Object, | 24842 type: Object, |
| 24843 observer: "_request", |
| 24368 }, | 24844 }, |
| 24369 | 24845 |
| 24370 //outputs | 24846 // outputs |
| 24371 busy: { | 24847 busy: { |
| 24372 type: Boolean, | 24848 type: Boolean, |
| 24373 computed: "_or(_busy1)", | 24849 computed: "_or(_busy1,_busy2,_busy3)", |
| 24850 notify: true, |
| 24851 }, |
| 24852 primary_map: { |
| 24853 type: Object, |
| 24854 computed: "_primaryMap(_tags,_dimensions,tasks)", |
| 24855 notify: true, |
| 24856 }, |
| 24857 primary_arr: { |
| 24858 type: Array, |
| 24859 computed: "_primaryArr(primary_map)", |
| 24374 notify: true, | 24860 notify: true, |
| 24375 }, | 24861 }, |
| 24376 tasks: { | 24862 tasks: { |
| 24377 type: Array, | 24863 type: Array, |
| 24378 computed: "_tasks(_list)", | 24864 computed: "_tasks(_list)", |
| 24379 notify: true, | 24865 notify: true, |
| 24866 }, |
| 24867 |
| 24868 // private |
| 24869 _busy1: { |
| 24870 type: Boolean, |
| 24871 value: false |
| 24872 }, |
| 24873 _busy2: { |
| 24874 type: Boolean, |
| 24875 value: false |
| 24876 }, |
| 24877 _busy3: { |
| 24878 type: Boolean, |
| 24879 value: false |
| 24880 }, |
| 24881 _dimensions: { |
| 24882 type: Object, |
| 24883 }, |
| 24884 _list: { |
| 24885 type: Object, |
| 24886 }, |
| 24887 _tags: { |
| 24888 type: Object, |
| 24889 }, |
| 24890 }, |
| 24891 |
| 24892 signIn: function(){ |
| 24893 this._getJsonAsync("_tags", "/_ah/api/swarming/v1/tasks/tags", |
| 24894 "_busy2", this.auth_headers); |
| 24895 this._getJsonAsync("_dimensions","/_ah/api/swarming/v1/bots/dimensions", |
| 24896 "_busy3", this.auth_headers); |
| 24897 |
| 24898 this._request(); |
| 24899 }, |
| 24900 |
| 24901 _primaryArr: function(map) { |
| 24902 var arr = Object.keys(map); |
| 24903 arr.sort(); |
| 24904 return arr; |
| 24905 }, |
| 24906 |
| 24907 _primaryMap: function(tags, dims, tasks) { |
| 24908 tags = (tags && tags.tasks_tags) || []; |
| 24909 dims = (dims && dims.bots_dimensions) || []; |
| 24910 tasks = tasks || []; |
| 24911 var map = {}; |
| 24912 // We combine all the tags reported by the tags endpoint, all known |
| 24913 // dimensions from the dimensions endpoint, and the tags seen in the |
| 24914 // returned tasks, just in case they didn't show up in the first two. |
| 24915 // This way a user can filter by what the data actually has and can |
| 24916 // discover new tags to filter by. |
| 24917 tags.forEach(function(t) { |
| 24918 if (!map[t.key]) { |
| 24919 map[t.key] = {}; |
| 24920 } |
| 24921 var values = t.value || []; |
| 24922 values.forEach(function(v) { |
| 24923 map[t.key][v] = true; |
| 24924 }) |
| 24925 }); |
| 24926 |
| 24927 dims.forEach(function(d) { |
| 24928 var vals = d.value; |
| 24929 if (!map[d.key]) { |
| 24930 map[d.key] = {}; |
| 24931 } |
| 24932 vals.forEach(function(v) { |
| 24933 map[d.key][v] = true; |
| 24934 }) |
| 24935 }); |
| 24936 |
| 24937 tasks.forEach(function(t) { |
| 24938 Object.keys(t.tagMap).forEach(function(k) { |
| 24939 var v = t.tagMap[k]; |
| 24940 if (!map[k]) { |
| 24941 map[k] = {}; |
| 24942 } |
| 24943 map[k][v] = true; |
| 24944 }); |
| 24945 }); |
| 24946 |
| 24947 // Turn the Map<Object,Map<Boolean>> into a Map<Object,Array<String>> |
| 24948 // with all of the aliases applied. |
| 24949 var pMap = {}; |
| 24950 for (key in map) { |
| 24951 var values = Object.keys(map[key]); |
| 24952 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(key) === -1) { |
| 24953 pMap[key] = values; |
| 24954 } else if (key === "gpu") { |
| 24955 var gpus = []; |
| 24956 values.forEach(function(g){ |
| 24957 var alias = swarming.alias.gpu(g); |
| 24958 if (alias !== "unknown") { |
| 24959 gpus.push(swarming.alias.apply(g, alias)); |
| 24960 } else { |
| 24961 gpus.push(g); |
| 24962 } |
| 24963 }.bind(this)); |
| 24964 pMap["gpu"] = gpus; |
| 24965 } else if (key === "device_type") { |
| 24966 var devs = []; |
| 24967 values.forEach(function(dt){ |
| 24968 var alias = swarming.alias.android(dt); |
| 24969 if (alias !== "unknown") { |
| 24970 devs.push(swarming.alias.apply(dt, alias)); |
| 24971 } else { |
| 24972 devs.push(dt); |
| 24973 } |
| 24974 }.bind(this)); |
| 24975 pMap["device_type"] = devs; |
| 24976 } else { |
| 24977 console.log("Unknown alias type: ", d); |
| 24978 } |
| 24380 } | 24979 } |
| 24980 |
| 24981 // Add some options that might not show up. |
| 24982 pMap["android_devices"].push("0"); |
| 24983 pMap["device_os"].push("none"); |
| 24984 pMap["device_type"].push("none"); |
| 24985 pMap["user"].push("none"); |
| 24986 |
| 24987 // Custom filter options |
| 24988 pMap["name"] = []; |
| 24989 pMap["state"] = ["PENDING", "RUNNING", "PENDING_RUNNING", "COMPLETED", |
| 24990 "COMPLETED_SUCCESS","COMPLETED_FAILURE", "EXPIRED", "TIMED_OUT", |
| 24991 "BOT_DIED", "CANCELED", "ALL", "DEDUPED"]; |
| 24992 pMap["abandoned_ts"] = []; |
| 24993 pMap["completed_ts"] = []; |
| 24994 pMap["costs_usd"] = []; |
| 24995 pMap["created_ts"] = []; |
| 24996 pMap["deduped_from"] = []; |
| 24997 pMap["duration"] = []; |
| 24998 pMap["modified_ts"] = []; |
| 24999 pMap["server_versions"] = []; |
| 25000 pMap["started_ts"] = []; |
| 25001 |
| 25002 return pMap; |
| 24381 }, | 25003 }, |
| 24382 signIn: function(){ | 25004 |
| 24383 // Auto on iron-ajax means to automatically re-make the request if | 25005 _request: function() { |
| 24384 // the url or the query params change. Auto does not trigger if the | 25006 // wait until the user has logged in before requesting this. |
| 24385 // [auth] headers change, so we wait until the user is signed in | 25007 if (!this.auth_headers) { |
| 24386 // before making any requests. | 25008 return; |
| 24387 this.$.tasklist.auto = true; | 25009 } |
| 25010 this._getJsonAsync("_list", "/_ah/api/swarming/v1/tasks/list", |
| 25011 "_busy1", this.auth_headers, this.query_params); |
| 24388 }, | 25012 }, |
| 24389 | 25013 |
| 24390 _tasks: function() { | 25014 _tasks: function() { |
| 24391 if (!this._list || !this._list.items) { | 25015 if (!this._list || !this._list.items) { |
| 24392 return []; | 25016 return []; |
| 24393 } | 25017 } |
| 24394 // Do any preprocessing here | 25018 // Do any preprocessing here |
| 25019 this._list.items.forEach(function(t) { |
| 25020 var tagMap = {}; |
| 25021 t.tags.forEach(function(tag) { |
| 25022 var split = tag.split(":", 1) |
| 25023 var key = split[0]; |
| 25024 var rest = tag.substring(key.length + 1); |
| 25025 tagMap[key] = rest; |
| 25026 }); |
| 25027 t.tagMap = tagMap; |
| 25028 }); |
| 24395 return this._list.items; | 25029 return this._list.items; |
| 24396 } | 25030 } |
| 24397 }); | 25031 }); |
| 24398 })(); | 25032 })(); |
| 24399 </script> | 25033 </script> |
| 24400 </dom-module> | 25034 </dom-module> |
| 24401 <dom-module id="task-list" assetpath="/res/imp/tasklist/"> | 25035 <dom-module id="task-list" assetpath="/res/imp/tasklist/"> |
| 24402 <template> | 25036 <template> |
| 24403 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-
style dynamic-table-style"> | 25037 <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-
style dynamic-table-style"> |
| 24404 | 25038 task-filters { |
| 25039 margin-bottom: 8px; |
| 25040 margin-right: 10px; |
| 25041 } |
| 24405 .task-list th > span { | 25042 .task-list th > span { |
| 24406 /* Leave space for sort-toggle*/ | 25043 /* Leave space for sort-toggle*/ |
| 24407 padding-right: 30px; | 25044 padding-right: 30px; |
| 24408 } | 25045 } |
| 25046 |
| 25047 /* These colors are from buildbot */ |
| 25048 .failed { |
| 25049 background-color: #ffdddd; |
| 25050 } |
| 25051 .died { |
| 25052 background-color: #cccccc; |
| 25053 } |
| 25054 .exception { |
| 25055 background-color: #edd2ff; |
| 25056 } |
| 25057 .pending { |
| 25058 background-color: #fffc6c; |
| 25059 } |
| 24409 </style> | 25060 </style> |
| 24410 | 25061 |
| 24411 <url-param name="sort" value="{{_sortstr}}" default_value="id:asc"> | 25062 <url-param name="sort" value="{{_sortstr}}" default_value="id:asc"> |
| 24412 </url-param> | 25063 </url-param> |
| 24413 | 25064 |
| 24414 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" sig
ned_in="{{_signed_in}}" busy="[[_busy]]" name="Swarming Task List"> | 25065 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per
missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw
arming Task List"> |
| 24415 | 25066 |
| 24416 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> | 25067 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> |
| 24417 | 25068 |
| 24418 <div hidden$="[[_not(_signed_in)]]"> | 25069 <div hidden$="[[_not(_signed_in)]]"> |
| 24419 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_
params]]" tasks="{{_items}}" busy="{{_busy}}"> | 25070 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_
params]]" tasks="{{_items}}" busy="{{_busy}}" primary_map="{{_primary_map}}" pri
mary_arr="{{_primary_arr}}"> |
| 24420 </task-list-data> | 25071 </task-list-data> |
| 24421 | 25072 |
| 25073 <paper-toast id="toast"></paper-toast> |
| 25074 |
| 24422 <div class="horizontal layout"> | 25075 <div class="horizontal layout"> |
| 24423 | 25076 |
| 24424 <task-filters columns="{{_columns}}" query_params="{{_query_params}}"
filter="{{_filter}}" verbose="{{_verbose}}"> | 25077 <task-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_a
rr]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter}
}"> |
| 24425 </task-filters> | 25078 </task-filters> |
| 24426 | 25079 |
| 24427 </div> | 25080 </div> |
| 24428 | 25081 |
| 24429 <table class="task-list"> | 25082 <table class="task-list"> |
| 24430 <thead on-sort_change="_sortChange"> | 25083 <thead on-sort_change="_sortChange"> |
| 24431 | 25084 |
| 24432 <tr> | 25085 <tr> |
| 24433 <th> | 25086 <th> |
| 24434 <span>Task Name</span> | 25087 <span>Task Name</span> |
| 24435 <sort-toggle name="name" current="[[_sort]]"> | 25088 <sort-toggle name="name" current="[[_sort]]"> |
| 24436 </sort-toggle> | 25089 </sort-toggle> |
| 24437 </th> | 25090 </th> |
| 24438 | 25091 |
| 24439 <th hidden$="[[_hide('state', _columns.*)]]"> | 25092 <th hidden$="[[_hide('state', _columns.*)]]"> |
| 24440 <span>Status</span> | 25093 <span>State</span> |
| 24441 <sort-toggle name="state" current="[[_sort]]"> | 25094 <sort-toggle name="state" current="[[_sort]]"> |
| 24442 </sort-toggle> | 25095 </sort-toggle> |
| 24443 </th> | 25096 </th> |
| 24444 | 25097 |
| 25098 <th hidden$="[[_hide('deduped_from', _columns.*)]]"> |
| 25099 <span>Deduped from</span> |
| 25100 <sort-toggle name="deduped_from" current="[[_sort]]"> |
| 25101 </sort-toggle> |
| 25102 </th> |
| 25103 |
| 24445 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> | 25104 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> |
| 24446 <th hidden$="[[_hide(c)]]"> | 25105 <th hidden$="[[_hide(c)]]"> |
| 24447 <span>[[_header(c)]]</span> | 25106 <span>[[_header(c)]]</span> |
| 24448 <sort-toggle name="[[c]]" current="[[_sort]]"> | 25107 <sort-toggle name="[[c]]" current="[[_sort]]"> |
| 24449 </sort-toggle> | 25108 </sort-toggle> |
| 24450 </th> | 25109 </th> |
| 24451 </template> | 25110 </template> |
| 24452 </tr> | 25111 </tr> |
| 24453 </thead> | 25112 </thead> |
| 24454 <tbody> | 25113 <tbody> |
| 24455 <template id="tasks_table" is="dom-repeat" items="[[_filteredSortedI
tems]]" as="task" initial-count="50"> | 25114 <template id="tasks_table" is="dom-repeat" items="[[_filteredSortedI
tems]]" as="task" initial-count="50"> |
| 24456 | 25115 |
| 24457 <tr class$="[[_taskClass(task)]]"> | 25116 <tr class$="[[_taskClass(task)]]"> |
| 24458 <td> | 25117 <td> |
| 24459 <a class="center" href$="[[_taskLink(task)]]" target="_blank"> | 25118 <a class="center" href$="[[_taskLink(task.task_id)]]" target="
_blank"> |
| 24460 [[task.name]] | 25119 [[task.name]] |
| 24461 </a> | 25120 </a> |
| 24462 </td> | 25121 </td> |
| 24463 <td hidden$="[[_hide('state', _columns.*)]]"> | 25122 <td hidden$="[[_hide('state', _columns.*)]]"> |
| 24464 [[_column('state', task, _verbose)]] | 25123 [[_column('state', task)]] |
| 24465 | 25124 <paper-button raised="" hidden$="[[_cannotCancel(task,_permiss
ions)]]" on-tap="_cancelTask"> |
| 25125 Cancel |
| 25126 </paper-button> |
| 25127 </td> |
| 25128 <td hidden$="[[_hide('deduped_from', _columns.*)]]"> |
| 25129 <a class="center" href$="[[_taskLink(task.deduped_from)]]" tar
get="_blank"> |
| 25130 [[_column('deduped_from',task)]] |
| 25131 </a> |
| 24466 </td> | 25132 </td> |
| 24467 | 25133 |
| 24468 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> | 25134 <template is="dom-repeat" items="[[_plainColumns]]" as="c"> |
| 24469 <td hidden$="[[_hide(c)]]"> | 25135 <td hidden$="[[_hide(c)]]"> |
| 24470 [[_column(c, task, _verbose)]] | 25136 [[_column(c, task)]] |
| 24471 </td> | 25137 </td> |
| 24472 </template> | 25138 </template> |
| 24473 | 25139 |
| 24474 </tr> | 25140 </tr> |
| 24475 </template> | 25141 </template> |
| 24476 </tbody> | 25142 </tbody> |
| 24477 </table> | 25143 </table> |
| 24478 </div> | 25144 </div> |
| 24479 | 25145 |
| 24480 </swarming-app> | 25146 </swarming-app> |
| 24481 | 25147 |
| 24482 </template> | 25148 </template> |
| 24483 <script> | 25149 <script> |
| 24484 (function(){ | 25150 (function(){ |
| 24485 var specialColumns = ["name", "state"]; | 25151 var specialColumns = ["deduped_from", "name", "state"]; |
| 24486 var columnMap = {}; | 25152 var columnMap = { |
| 25153 costs_usd: function(task) { |
| 25154 return this._attribute(task, "costs_usd", 0)[0]; |
| 25155 }, |
| 25156 state: function(task) { |
| 25157 var state = this._attribute(task, "state")[0]; |
| 25158 if (state === "COMPLETED") { |
| 25159 |
| 25160 if (this._attribute(task, "failure", false)[0]) { |
| 25161 return "COMPLETED (FAILURE)"; |
| 25162 } |
| 25163 var tryNum = this._attribute(task, "try_number", "-1")[0]; |
| 25164 if (tryNum === "0") { |
| 25165 return "COMPLETED (DEDUPED)"; |
| 25166 } |
| 25167 return "COMPLETED (SUCCESS)"; |
| 25168 } |
| 25169 return state; |
| 25170 }, |
| 25171 }; |
| 24487 var headerMap = { | 25172 var headerMap = { |
| 24488 "user": "Requesting User", | 25173 "user": "Requesting User", |
| 24489 }; | 25174 }; |
| 24490 var specialSort = {}; | 25175 var specialSort = {}; |
| 24491 | 25176 |
| 24492 Polymer({ | 25177 Polymer({ |
| 24493 is: 'task-list', | 25178 is: 'task-list', |
| 24494 behaviors: [ | 25179 behaviors: [ |
| 24495 SwarmingBehaviors.DynamicTableBehavior, | 25180 SwarmingBehaviors.DynamicTableBehavior, |
| 24496 ], | 25181 ], |
| 24497 | 25182 |
| 24498 properties: { | 25183 properties: { |
| 24499 client_id: { | 25184 client_id: { |
| 24500 type: String, | 25185 type: String, |
| 24501 }, | 25186 }, |
| 24502 | 25187 |
| 24503 // For dynamic table. | 25188 // For dynamic table. |
| 24504 _columnMap: { | 25189 _columnMap: { |
| 24505 type: Object, | 25190 type: Object, |
| 24506 value: columnMap, | 25191 value: function() { |
| 25192 var base = this._commonColumns(); |
| 25193 for (var attr in columnMap) { |
| 25194 base[attr] = columnMap[attr]; |
| 25195 } |
| 25196 return base; |
| 25197 }, |
| 24507 }, | 25198 }, |
| 24508 _headerMap: { | 25199 _headerMap: { |
| 24509 type: Object, | 25200 type: Object, |
| 24510 value: headerMap, | 25201 value: headerMap, |
| 24511 }, | 25202 }, |
| 24512 _specialColumns: { | 25203 _specialColumns: { |
| 24513 type: Array, | 25204 type: Array, |
| 24514 value: specialColumns, | 25205 value: specialColumns, |
| 24515 }, | 25206 }, |
| 24516 _specialSort: { | 25207 _specialSort: { |
| 24517 type: Object, | 25208 type: Object, |
| 24518 value: specialSort, | 25209 value: specialSort, |
| 24519 }, | 25210 }, |
| 24520 }, | 25211 }, |
| 24521 | 25212 |
| 24522 _attribute: function(task, col, def) { | 25213 _attribute: function(task, col, def) { |
| 24523 var retVal = task[col] || [def]; | 25214 if (def === undefined) { |
| 25215 def = "none"; |
| 25216 } |
| 25217 var retVal = this._tag(task, col) || task[col] || [def]; |
| 24524 if (!Array.isArray(retVal)) { | 25218 if (!Array.isArray(retVal)) { |
| 24525 return [retVal]; | 25219 return [retVal]; |
| 24526 } | 25220 } |
| 24527 return retVal; | 25221 return retVal; |
| 24528 }, | 25222 }, |
| 24529 | 25223 |
| 24530 _taskLink: function(task) { | 25224 _cannotCancel: function(task, permissions) { |
| 25225 return !(permissions && permissions.can_cancel_task && |
| 25226 this._column("state", task) === "PENDING"); |
| 25227 }, |
| 25228 |
| 25229 _cancelTask: function(e) { |
| 25230 var task = e.model.task; |
| 25231 if (!task || !task.task_id) { |
| 25232 console.log("Missing task info", task); |
| 25233 return |
| 25234 } |
| 25235 var id = task.task_id |
| 25236 |
| 25237 // Keep toast displayed until we hear back from the cancel. |
| 25238 this.$.toast.duration = 0; |
| 25239 this.$.toast.text="Canceling task " + id; |
| 25240 this.$.toast.open(); |
| 25241 var url = "/_ah/api/swarming/v1/task/" + id +"/cancel"; |
| 25242 sk.request("POST", url, undefined, this._auth_headers).then(function(res
ponse) { |
| 25243 this.$.toast.close(); |
| 25244 this.$.toast.show({ |
| 25245 text: "Request sent. Response: "+response, |
| 25246 duration: 3000, |
| 25247 }); |
| 25248 }.bind(this)).catch(function(reason) { |
| 25249 console.log("Cancellation failed", reason); |
| 25250 this.$.toast.close(); |
| 25251 this.$.toast.show({ |
| 25252 text: "Request failed. Reason: "+reason, |
| 25253 duration: 3000, |
| 25254 }); |
| 25255 }.bind(this)); |
| 25256 }, |
| 25257 |
| 25258 _tag: function(task, col) { |
| 25259 if (!task || !task.tagMap) { |
| 25260 return undefined; |
| 25261 } |
| 25262 return task.tagMap[col]; |
| 25263 }, |
| 25264 |
| 25265 _taskLink: function(taskId) { |
| 25266 if (!taskId) { |
| 25267 return undefined; |
| 25268 } |
| 24531 // TODO(kjlubick) Make this point to /newui/ when appropriate. | 25269 // TODO(kjlubick) Make this point to /newui/ when appropriate. |
| 24532 return "/restricted/task/"+task.task_id; | 25270 return "/restricted/task/"+taskId; |
| 24533 }, | 25271 }, |
| 24534 | 25272 |
| 24535 _taskClass: function(task) { | 25273 _taskClass: function(task) { |
| 24536 // TODO(kjlubick): Color tasks? | 25274 var state = this._column("state", task); |
| 25275 if (state === "CANCELED" ||state === "TIMED_OUT" || state === "EXPIRED")
{ |
| 25276 return "exception"; |
| 25277 } |
| 25278 if (state === "BOT_DIED") { |
| 25279 return "died"; |
| 25280 } |
| 25281 if (state === "COMPLETED (FAILURE)") { |
| 25282 return "failed"; |
| 25283 } |
| 25284 if (state === "RUNNING" || state === "PENDING") { |
| 25285 return "pending"; |
| 25286 } |
| 24537 return ""; | 25287 return ""; |
| 24538 } | 25288 } |
| 24539 | 25289 |
| 24540 }); | 25290 }); |
| 24541 })(); | 25291 })(); |
| 24542 </script> | 25292 </script> |
| 24543 </dom-module></div></body></html> | 25293 </dom-module></div></body></html> |
| OLD | NEW |