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