| Index: appengine/swarming/ui/build/elements.html
|
| diff --git a/appengine/swarming/ui/build/elements.html b/appengine/swarming/ui/build/elements.html
|
| index 8b744dce8b5a07d9b013f92063a558c49a1c3904..d3497dfded8e64f61b70eb80b0de445d75d74c44 100644
|
| --- a/appengine/swarming/ui/build/elements.html
|
| +++ b/appengine/swarming/ui/build/elements.html
|
| @@ -885,7 +885,7 @@ the fleet."> <template is="dom-repeat" items="[[_filters]]" as="fil"> <div class
|
| });
|
| },
|
| });
|
| - })() </script> </dom-module><dom-module id="task-list" assetpath="/res/imp/tasklist/"> <template> <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style dynamic-table-style task-style">task-filters{margin-bottom:8px;margin-right:10px}.task-list th>span{padding-right:30px}</style> <url-param name="s" value="{{_sortstr}}" default_value="created_ts:desc"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,_busy2)]]" name="Swarming Task List"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-list-data id="data" auth_headers="[[_auth_headers]]" query_params="[[_query_params]]" tasks="[[_items]]" busy="{{_busy1)}}" dimensions="{{_dimensions}}" primary_map="{{_primary_map}}" primary_arr="{{_primary_arr}}"> </task-list-data> <div class="horizontal layout"> <task-filters dimensions="[[_dimensions]]" permissions="[[_permissions]]" primary_map="[[_primary_map]]" primary_arr="[[_primary_arr]]" special_columns="[[_specialColumns]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter}}" on-cancel-all="_promptCancelAll"> </task-filters> </div> <table class="task-list"> <thead on-sort_change="_sortChange"> <tr> <th> <span>Task Name</span> <sort-toggle name="name" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('state', _columns.*)]]"> <span>State</span> <sort-toggle name="state" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('bot', _columns.*)]]"> <span>Bot Assigned</span> <sort-toggle name="bot" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('deduped_from', _columns.*)]]"> <span>Deduped from</span> <sort-toggle name="deduped_from" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('source_revision', _columns.*)]]"> <span>Source Revision</span> <sort-toggle name="source_revision" current="[[_sort]]"> </sort-toggle> </th> <template is="dom-repeat" items="[[_plainColumns]]" as="c"> <th hidden$="[[_hide(c)]]"> <span>[[_header(c)]]</span> <sort-toggle name="[[c]]" current="[[_sort]]"> </sort-toggle> </th> </template> </tr> </thead> <tbody> <template id="tasks_table" is="dom-repeat" items="[[_filteredSortedItems]]" as="task" initial-count="50"> <tr class$="[[_taskClass(task)]]"> <td> <a class="center" href$="[[_taskLink(task.task_id)]]" target="_blank"> [[task.name]] </a> </td> <td hidden$="[[_hide('state', _columns.*)]]"> [[_column('state', task)]] <paper-button raised="" hidden$="[[_cannotCancel(task,_permissions)]]" on-tap="_promptCancel"> Cancel </paper-button> </td> <td hidden$="[[_hide('bot', _columns.*)]]"> <a class="center" href$="[[_botLink(task.bot_id)]]" target="_blank"> [[_column('bot',task)]] </a> </td> <td hidden$="[[_hide('deduped_from', _columns.*)]]"> <a class="center" href$="[[_taskLink(task.deduped_from)]]" target="_blank"> [[_column('deduped_from',task)]] </a> </td> <td hidden$="[[_hide('source_revision', _columns.*)]]"> <a class="center" href$="[[_sourceLink(task)]]" target="_blank"> [[_column('source_revision',task)]] </a> </td> <template is="dom-repeat" items="[[_plainColumns]]" as="c"> <td hidden$="[[_hide(c)]]"> [[_column(c, task)]] </td> </template> </tr> </template> </tbody> </table> <pageable-data id="page_tasks" busy="{{_busy2}}" label="Show more tasks" output="{{_items}}" parse="[[_parseTasks]]"> </pageable-data> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialogPrompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <paper-dialog id="cancel_all_dialog" modal=""> <task-mass-cancel id="mass_cancel" auth_headers="[[_auth_headers]]" started_canceling="{{_started_canceling}}" finished_canceling="{{_finished_canceling}}"> </task-mass-cancel> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="" hidden$="[[_started_canceling]]"> Go Back - Don't Cancel Anything </paper-button> <paper-button dialog-dismiss="" autofocus="" hidden$="[[!_finished_canceling]]"> Done </paper-button> </div> </paper-dialog> </template> <script>!function(){function t(t){return function(e){return this._attribute(e,"human_"+t)[0]}}function e(t){return function(e,a,s){var n=this._attribute(a,t,"0")[0],i=this._attribute(s,t,"0")[0];return e*(n-i)}}var a=["deduped_from","name","state","bot","source_revision"],s={abandoned_ts:t("abandoned_ts"),bot:function(t){return this._attribute(t,"bot_id")[0]},completed_ts:t("completed_ts"),costs_usd:function(t){return this._attribute(t,"costs_usd",0)[0]},created_ts:t("created_ts"),duration:t("duration"),modified_ts:t("modified_ts"),source_revision:function(t){var e=this._attribute(t,"source_revision")[0];return e.substring(0,8)},started_ts:t("started_ts"),state:function(t){var e=this._attribute(t,"state")[0];if("COMPLETED"===e){if(this._attribute(t,"failure",!1)[0])return"COMPLETED (FAILURE)";var a=this._attribute(t,"try_number","-1")[0];return"0"===a?"COMPLETED (DEDUPED)":"COMPLETED (SUCCESS)"}return e}},n={abandoned_ts:"Abandoned On",completed_ts:"Completed On",created_ts:"Created On",duration:"Duration",modified_ts:"Last Modified",started_ts:"Started Working On",user:"Requesting User"},i={abandoned_ts:e("abandoned_ts"),completed_ts:e("completed_ts"),created_ts:e("created_ts"),duration:e("duration"),modified_ts:e("modified_ts"),started_ts:e("started_ts")};Polymer({is:"task-list",behaviors:[SwarmingBehaviors.DynamicTableBehavior,SwarmingBehaviors.TaskBehavior],properties:{client_id:{type:String},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_parseTasks:{type:Function,value:function(){return this.$.data.parseTasks.bind(this)}},_toCancel:{type:String},_columnMap:{type:Object,value:function(){var t=this._commonColumns();for(var e in s)t[e]=s[e];return t}},_headerMap:{type:Object,value:n},_specialColumns:{type:Array,value:a},_specialSort:{type:Object,value:i}},observers:["reload(_query_params,_auth_headers)"],_attribute:function(t,e,a){void 0===a&&(a="none");var s=this._tag(t,e)||t[e]||[a];return Array.isArray(s)?s:[s]},_cannotCancel:function(t,e){return!(e&&e.cancel_task&&"PENDING"===this._column("state",t))},_cancelTask:function(){var t="/api/swarming/v1/task/"+this._toCancel+"/cancel";swarming.postWithToast(t,"Canceling task "+this._toCancel,this._auth_headers),this.set("_toCancel","")},_promptClosed:function(t){t.detail.confirmed&&this._cancelTask()},_promptCancel:function(t){var e=t.model.task;return e&&e.task_id?(this.set("_toCancel",e.task_id),this.set("_dialogPrompt",'cancel task "'+e.name+'"'),void this.$.prompt.open()):void console.log("Missing task info",e)},_promptCancelAll:function(t){this.$.mass_cancel.tags=t.detail.tags,this.$.mass_cancel.prompt(),this.$.cancel_all_dialog.open()},_closeCancelAll:function(){this.$.cancel_all_dialog.close()},reload:function(){if(this._auth_headers&&this._query_params){var t="/api/swarming/v1/tasks/list?"+sk.query.fromParamSet(this._query_params);this.$.page_tasks.load(t,this._auth_headers)}},_sourceLink:function(t){var e=this._attribute(t,"source_revision")[0],a=this._attribute(t,"source_repo")[0];return"none"!==e&&"none"!==a&&a.replace("%s",e)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_taskClass:function(t){return this.stateClass(this._column("state",t))}})}()</script> </dom-module> <dom-module id="iron-collapse" assetpath="/res/imp/bower_components/iron-collapse/"> <template> <style>:host{display:block;transition-duration:var(--iron-collapse-transition-duration,300ms);overflow:visible}:host(.iron-collapse-closed){display:none}:host(:not(.iron-collapse-opened)){overflow:hidden}</style> <content></content> </template> </dom-module> <script>Polymer({is:"iron-collapse",behaviors:[Polymer.IronResizableBehavior],properties:{horizontal:{type:Boolean,value:!1,observer:"_horizontalChanged"},opened:{type:Boolean,value:!1,notify:!0,observer:"_openedChanged"},noAnimation:{type:Boolean},_desiredSize:{type:String,value:""}},get dimension(){return this.horizontal?"width":"height"},get _dimensionMax(){return this.horizontal?"maxWidth":"maxHeight"},get _dimensionMaxCss(){return this.horizontal?"max-width":"max-height"},hostAttributes:{role:"group","aria-hidden":"true","aria-expanded":"false"},listeners:{transitionend:"_transitionEnd"},attached:function(){this._transitionEnd()},toggle:function(){this.opened=!this.opened},show:function(){this.opened=!0},hide:function(){this.opened=!1},updateSize:function(i,t){if(i="auto"===i?"":i,this._desiredSize!==i){this._desiredSize=i,this._updateTransition(!1);var e=t&&!this.noAnimation&&this._isDisplayed;if(e){var n=this._calcSize();""===i&&(this.style[this._dimensionMax]="",i=this._calcSize()),this.style[this._dimensionMax]=n,this.scrollTop=this.scrollTop,this._updateTransition(!0),e=i!==n}this.style[this._dimensionMax]=i,e||this._transitionEnd()}},enableTransition:function(i){Polymer.Base._warn("`enableTransition()` is deprecated, use `noAnimation` instead."),this.noAnimation=!i},_updateTransition:function(i){this.style.transitionDuration=i&&!this.noAnimation?"":"0s"},_horizontalChanged:function(){this.style.transitionProperty=this._dimensionMaxCss;var i="maxWidth"===this._dimensionMax?"maxHeight":"maxWidth";this.style[i]="",this.updateSize(this.opened?"auto":"0px",!1)},_openedChanged:function(){this.setAttribute("aria-expanded",this.opened),this.setAttribute("aria-hidden",!this.opened),this.toggleClass("iron-collapse-closed",!1),this.toggleClass("iron-collapse-opened",!1),this.updateSize(this.opened?"auto":"0px",!0),this.opened&&this.focus()},_transitionEnd:function(){this.style[this._dimensionMax]=this._desiredSize,this.toggleClass("iron-collapse-closed",!this.opened),this.toggleClass("iron-collapse-opened",this.opened),this._updateTransition(!1),this.notifyResize()},get _isDisplayed(){var i=this.getBoundingClientRect();for(var t in i)if(0!==i[t])return!0;return!1},_calcSize:function(){return this.getBoundingClientRect()[this.dimension]+"px"}})</script> <script>Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(e){this.focusedItem.click(),e.detail.keyboardEvent.preventDefault()},_onDownKey:function(e){this.focusedItem.click(),e.detail.keyboardEvent.preventDefault()},get _isRTL(){return"rtl"===window.getComputedStyle(this).direction},_onLeftKey:function(e){this._isRTL?this._focusNext():this._focusPrevious(),e.detail.keyboardEvent.preventDefault()},_onRightKey:function(e){this._isRTL?this._focusPrevious():this._focusNext(),e.detail.keyboardEvent.preventDefault()},_onKeydown:function(e){this.keyboardEventMatchesKeys(e,"up down left right esc")||this._focusWithKeyboardEvent(e)}},Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl]</script> <iron-iconset-svg name="paper-tabs" size="24"> <svg><defs> <g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path></g> <g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></g> </defs></svg> </iron-iconset-svg> <dom-module id="paper-tab" assetpath="/res/imp/bower_components/paper-tabs/"> <template> <style>:host{@apply(--layout-inline);@apply(--layout-center);@apply(--layout-center-justified);@apply(--layout-flex-auto);position:relative;padding:0 12px;overflow:hidden;cursor:pointer;vertical-align:middle;@apply(--paper-font-common-base);@apply(--paper-tab)}:host(:focus){outline:0}:host([link]){padding:0}.tab-content{height:100%;transform:translateZ(0);-webkit-transform:translateZ(0);transition:opacity .1s cubic-bezier(.4,0,1,1);@apply(--layout-horizontal);@apply(--layout-center-center);@apply(--layout-flex-auto);@apply(--paper-tab-content)}:host(:not(.iron-selected))>.tab-content{opacity:.8;@apply(--paper-tab-content-unselected)}:host(:focus) .tab-content{opacity:1;font-weight:700}paper-ripple{color:var(--paper-tab-ink,--paper-yellow-a100)}.tab-content>::content>a{@apply(--layout-flex-auto);height:100%}</style> <div class="tab-content"> <content></content> </div> </template> <script>Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:!1,reflectToAttribute:!0}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var t=Polymer.dom(this).parentNode;return!!t&&!!t.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(t){if(this.link){var e=this.queryEffectiveChildren("a");if(!e)return;if(t.target===e)return;e.click()}}})</script> </dom-module> <dom-module id="paper-tabs" assetpath="/res/imp/bower_components/paper-tabs/"> <template> <style>:host{@apply(--layout);@apply(--layout-center);height:48px;font-size:14px;font-weight:500;overflow:hidden;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:transparent;@apply(--paper-tabs)}:host-context([dir=rtl]){@apply(--layout-horizontal-reverse)}#tabsContainer{position:relative;height:100%;white-space:nowrap;overflow:hidden;@apply(--layout-flex-auto)}#tabsContent{height:100%;-moz-flex-basis:auto;-ms-flex-basis:auto;flex-basis:auto}#tabsContent.scrollable{position:absolute;white-space:nowrap}#tabsContent.scrollable.fit-container,#tabsContent:not(.scrollable){@apply(--layout-horizontal)}#tabsContent.scrollable.fit-container{min-width:100%}#tabsContent.scrollable.fit-container>::content>*{-ms-flex:1 0 auto;-webkit-flex:1 0 auto;flex:1 0 auto}.hidden{display:none}.not-visible{opacity:0;cursor:default}paper-icon-button{width:48px;height:48px;padding:12px;margin:0 4px}#selectionBar{position:absolute;height:2px;bottom:0;left:0;right:0;background-color:var(--paper-tabs-selection-bar-color,--paper-yellow-a100);-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:left center;transform-origin:left center;transition:-webkit-transform;transition:transform;@apply(--paper-tabs-selection-bar)}#selectionBar.align-bottom{top:0;bottom:auto}#selectionBar.expand{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,1,1)}#selectionBar.contract{transition-duration:.18s;transition-timing-function:cubic-bezier(0,0,.2,1)}#tabsContent>::content>:not(#selectionBar){height:100%}</style> <paper-icon-button icon="paper-tabs:chevron-left" class$="[[_computeScrollButtonClass(_leftHidden, scrollable, hideScrollButtons)]]" on-up="_onScrollButtonUp" on-down="_onLeftScrollButtonDown" tabindex="-1"></paper-icon-button> <div id="tabsContainer" on-track="_scroll" on-down="_down"> <div id="tabsContent" class$="[[_computeTabsContentClass(scrollable, fitContainer)]]"> <div id="selectionBar" class$="[[_computeSelectionBarClass(noBar, alignBottom)]]" on-transitionend="_onBarTransitionEnd"></div> <content select="*"></content> </div> </div> <paper-icon-button icon="paper-tabs:chevron-right" class$="[[_computeScrollButtonClass(_rightHidden, scrollable, hideScrollButtons)]]" on-up="_onScrollButtonUp" on-down="_onRightScrollButtonDown" tabindex="-1"></paper-icon-button> </template> <script>Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:!1,observer:"_noinkChanged"},noBar:{type:Boolean,value:!1},noSlide:{type:Boolean,value:!1},scrollable:{type:Boolean,value:!1},fitContainer:{type:Boolean,value:!1},disableDrag:{type:Boolean,value:!1},hideScrollButtons:{type:Boolean,value:!1},alignBottom:{type:Boolean,value:!1},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:!1},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:!1},_rightHidden:{type:Boolean,value:!1},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null,this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0,this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this),this.addEventListener("blur",this._onBlurCapture.bind(this),!0)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(t){var e=Polymer.dom(this).querySelectorAll("paper-tab");e.forEach(t?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(t){t.setAttribute("noink","")},_removeNoinkAttribute:function(t){t.removeAttribute("noink")},_computeScrollButtonClass:function(t,e,i){return!e||i?"hidden":t?"not-visible":""},_computeTabsContentClass:function(t,e){return t?"scrollable"+(e?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(t,e){return t?"hidden":e?"align-bottom":""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll(),this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(t){this._tabChanged(t.detail.item,this._previousTab),this._previousTab=t.detail.item,this.cancelDebouncer("tab-changed")},_onIronDeselect:function(t){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab),this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation(),Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(t,e){this._pendingActivationItem=t,this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,e)},_delayedActivationHandler:function(){var t=this._pendingActivationItem;this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0,t.fire(this.activateEvent,null,{bubbles:!0,cancelable:!0})},_cancelPendingActivation:function(){void 0!==this._pendingActivationTimeout&&(this.cancelAsync(this._pendingActivationTimeout),this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0)},_onArrowKeyup:function(t){this.autoselect&&this._scheduleActivation(this.focusedItem,this.autoselectDelay)},_onBlurCapture:function(t){t.target===this._pendingActivationItem&&this._cancelPendingActivation()},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(t,e){if(this.scrollable){var i=e&&-e.ddx||0;this._affectScroll(i)}},_down:function(t){this.async(function(){this._defaultFocusAsync&&(this.cancelAsync(this._defaultFocusAsync),this._defaultFocusAsync=null)},1)},_affectScroll:function(t){this.$.tabsContainer.scrollLeft+=t;var e=this.$.tabsContainer.scrollLeft;this._leftHidden=0===e,this._rightHidden=e===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft(),this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight(),this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob),this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(t,e){if(!t)return this.$.selectionBar.classList.remove("expand"),this.$.selectionBar.classList.remove("contract"),void this._positionBar(0,0);var i=this.$.tabsContent.getBoundingClientRect(),n=i.width,o=t.getBoundingClientRect(),s=o.left-i.left;if(this._pos={width:this._calcPercent(o.width,n),left:this._calcPercent(s,n)},this.noSlide||null==e)return this.$.selectionBar.classList.remove("expand"),this.$.selectionBar.classList.remove("contract"),void this._positionBar(this._pos.width,this._pos.left);var a=e.getBoundingClientRect(),l=this.items.indexOf(e),c=this.items.indexOf(t),r=5;this.$.selectionBar.classList.add("expand");var h=l<c,d=this._isRTL;d&&(h=!h),h?this._positionBar(this._calcPercent(o.left+o.width-a.left,n)-r,this._left):this._positionBar(this._calcPercent(a.left+a.width-o.left,n)-r,this._calcPercent(s,n)+r),this.scrollable&&this._scrollToSelectedIfNeeded(o.width,s)},_scrollToSelectedIfNeeded:function(t,e){var i=e-this.$.tabsContainer.scrollLeft;i<0?this.$.tabsContainer.scrollLeft+=i:(i+=t-this.$.tabsContainer.offsetWidth,i>0&&(this.$.tabsContainer.scrollLeft+=i))},_calcPercent:function(t,e){return 100*t/e},_positionBar:function(t,e){t=t||0,e=e||0,this._width=t,this._left=e,this.transform("translateX("+e+"%) scaleX("+t/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(t){var e=this.$.selectionBar.classList;e.contains("expand")?(e.remove("expand"),e.add("contract"),this._positionBar(this._pos.width,this._pos.left)):e.contains("contract")&&e.remove("contract")}})</script> </dom-module> <dom-module id="single-page-style" assetpath="/res/imp/common/"> <template> <style>.header{max-width:800px}.title{font-size:1.5em;font-weight:700;margin:5px}.id_input{margin-left:5px;--paper-input-container-input:{font-size:2em};}.refresh{max-width:40px;max-height:40px;width:initial;height:initial}button{min-width:4em;max-height:55px}table{border-collapse:collapse;margin-left:5px;margin-bottom:8px}td,th{border:1px solid #BBB;padding:5px}.tabs{background-color:#1F78B4;color:#fff;max-width:600px;margin-left:5px;--paper-checkbox-label-color:#fff}paper-tab{background-color:#A6CEE3;color:#000}paper-tab.iron-selected{background-color:#1F78B4;color:#fff;font-weight:700;text-decoration:underline}paper-tab[disabled]{background-color:#AAA;text-decoration:line-through}.quarantined{background-color:#fdd}.dead{background-color:#ccc}</style> </template> </dom-module><script>!function(){SwarmingBehaviors.BotPageBehavior=[SwarmingBehaviors.CommonBehavior,{}]}()</script> <dom-module id="bot-page-data" assetpath="/res/imp/botpage/"> <script>!function(){function t(t){if(!s){var e=t.toString();s=e.substring(e.indexOf("("))}return t.toLocaleString()+" "+s}var e,s,i=400,n=["first_seen_ts","last_seen_ts","lease_expiration_ts"],a=["started_ts","completed_ts","abandoned_ts","modified_ts"];Polymer({is:"bot-page-data",behaviors:[SwarmingBehaviors.BotPageBehavior],properties:{auth_headers:{type:Object},bot_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1)",notify:!0},bot:{type:Object,computed:"_parseBot(_bot)",notify:!0},bot_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_bot:{type:Object},_events:{type:Object},_tasks:{type:Object}},observers:["request(auth_headers,bot_id)"],request:function(){this.bot_id&&this.auth_headers&&(e&&this.cancelAsync(e),e=this.async(function(){e=void 0;var t="/api/swarming/v1/bot/"+this.bot_id,s=this._getJsonAsync("_bot",t+"/get","_busy1",this.auth_headers);s.then(function(){this.set("bot_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("bot_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this.fire("reload",{id:this.bot_id})},i))},_parseBot:function(e){if(!e)return{};e.state=e.state||"{}",e.state=JSON.parse(e.state)||{};var s=e.state.disks||{},i=Object.keys(s);if(i.length){e.disks=[];for(var a=0;a<i.length;a++)e.disks.push({id:i[a],mb:s[i[a]].free_mb});e.disks.sort(function(t,e){return e.mb-t.mb})}else e.disks=[{id:"unknown",mb:0}];return e.dimensions=e.dimensions||[],e.dimensions.forEach(function(t){swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(t.key)!==-1&&t.value.forEach(function(e,s){t.value[s]=swarming.alias.apply(e,t.key)})}),n.forEach(function(s){e[s]&&(e[s]=new Date(e[s]),e["human_"+s]=t(e[s]))}),e},parseEvents:function(e){if(!e||!e.items)return[];var e=e.items;return e.forEach(function(e){e.ts&&(e.ts=new Date(e.ts),e.human_ts=t(e.ts))}),e.sort(function(t,e){return e.ts-t.ts}),e},parseTasks:function(e){if(!e||!e.items)return[];var e=e.items;return e.forEach(function(e){if(a.forEach(function(s){e[s]&&(e[s]=new Date(e[s]),e["human_"+s]=t(e[s]))}),e.duration)e.human_duration=this._humanDuration(e.duration);else{var s=e.completed_ts||e.abandoned_ts||e.modified_ts||new Date;e.human_duration=this._timeDiffExact(e.started_ts,s),e.duration=(s.getTime()-e.started_ts)/1e3}e.state=e.state||"UNKNOWN","COMPLETED"===e.state&&(e.failure?e.state="FAILURE":e.state="SUCCESS")}.bind(this)),e.sort(function(t,e){return e.started_ts-t.started_ts}),e}})}()</script> </dom-module> <dom-module id="bot-page-summary" assetpath="/res/imp/botpage/"> <template> <style include="single-page-style">.wrapper{display:table;margin-left:auto;margin-bottom:10px;margin-right:5px}paper-checkbox{margin-left:5px}.thick{border-top-style:solid}</style> <url-param name="show_full_names" value="{{_show_full_names}}"> </url-param> <url-param name="show_all_tasks" value="{{_show_all_tasks}}"> </url-param> <url-param name="sort_stats" value="{{_sortstr}}" default_value="total:desc"> </url-param> <div class="wrapper"> <table> <thead on-sort_change="_sortChange"> <tr> <th> <span>Name</span> <sort-toggle name="full_name" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Total</span> <sort-toggle name="total" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Success</span> <sort-toggle name="success" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Failed</span> <sort-toggle name="failed" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Died</span> <sort-toggle name="bot_died" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Average Duration</span> <sort-toggle name="avg_duration" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Total Duration</span> <sort-toggle name="total_time" current="[[_sort]]"> </sort-toggle> </th> <th>Percent of Total</th> </tr> </thead> <tbody> <template is="dom-repeat" items="[[_tasksToShow]]" as="task"> <tr> <td hidden$="[[_truthy(_show_full_names)]]" title="[[task.full_name]]">[[task.name]]</td> <td hidden$="[[_not(_show_full_names)]]" title="[[task.full_name]]">[[task.full_name]]</td> <td>[[task.total]]</td> <td>[[task.success]]</td> <td>[[task.failed]]</td> <td>[[task.bot_died]]</td> <td>[[_humanDuration(task.avg_duration)]]</td> <td>[[_humanDuration(task.total_time)]]</td> <td>[[task.total_time_percent]]%</td> </tr> </template> </tbody> <tbody><tr class="thick"> <td>Total</td> <td>[[_totalStats.total]]</td> <td>[[_totalStats.success]]</td> <td>[[_totalStats.failed]]</td> <td>[[_totalStats.bot_died]]</td> <td>[[_humanDuration(_totalStats.avg_duration)]]</td> <td>[[_humanDuration(_totalStats.total_time)]]</td> <td>100.0%</td> </tr> </tbody></table> <div> <table> <thead> <tr> <th title="How much time passed between the oldest task fetched and now."> Total Wall Time </th> <th title="How much of the wall time this bot was busy with a task."> Wall Time Utilization </th> </tr> </thead> <tbody> <tr> <td>[[_humanDuration(_totalStats.wall_time)]]</td> <td>[[_totalStats.wall_time_utilization]]%</td> </tr> </tbody> </table> <paper-checkbox checked="{{_show_full_names}}"> Show Full Names </paper-checkbox> <paper-checkbox hidden$="[[_cannotExpand]]" checked="{{_show_all_tasks}}"> Show All Tasks </paper-checkbox> </div> </div> </template> <script>!function(){var t=15;Polymer({is:"bot-page-summary",behaviors:[SwarmingBehaviors.BotPageBehavior],properties:{tasks:{type:Array},_cannotExpand:{type:Boolean,computed:"_countTasks(_taskStats.*)"},_show_all_tasks:{type:Boolean},_show_full_names:{type:Boolean},_sortstr:{type:String},_sort:{type:Object,computed:"_makeSortObject(_sortstr)"},_taskStats:{type:Array},_tasksToShow:{type:Array,computed:"_sortAndLimitTasks(_taskStats.*,_sort.*,_show_all_tasks)"},_totalStats:{type:Object}},observers:["_aggregate(tasks.*)"],_aggregate:function(){if(this.tasks&&this.tasks.length){var t=new Date(1e3*sk.now()),a={},e={total:this.tasks.length,success:0,failed:0,bot_died:0,avg_duration:0,total_time:0,wall_time:(t-this.tasks[this.tasks.length-1].started_ts)/1e3};this.tasks.forEach(function(t){var s=t.name.trim(),i=s.split("/");5===i.length&&(s=i[0]+"/"+i[3]),a[s]||(a[s]={full_name:s,name:s,total:0,success:0,failed:0,bot_died:0,avg_duration:0,total_time:0}),a[s].total++,t.failure?(e.failed++,a[s].failed++):t.internal_failure?(e.bot_died++,a[s].bot_died++):(e.success++,a[s].success++),e.total_time+=t.duration,a[s].total_time+=t.duration}),e.avg_duration=e.total_time/e.total,e.wall_time_utilization=(100*e.total_time/e.wall_time).toFixed(1),this.set("_totalStats",e);var s=Object.keys(a),i=[];s.forEach(function(t){a[t].avg_duration=a[t].total_time/a[t].total,a[t].total_time_percent=(100*a[t].total_time/e.total_time).toFixed(1),i.push(a[t])});var o=new Substrings({minOccurrence:Math.max(2,s.length-1),minLength:6});o.build(s);var n=o.weighByAverage()||[];n.length&&n[0].source.forEach(function(t){var a=i[t].full_name;i[t].name=a.replace(n[0].name,"...")}),this.set("_taskStats",i)}},_compare:function(t,a){if(!this._sort)return 0;var e=1;return"desc"===this._sort.direction&&(e=-1),e*swarming.naturalCompare(t[this._sort.name],a[this._sort.name])},_countTasks:function(){return this._taskStats.length<=t},_makeSortObject:function(t){if(t){var a=t.split(":");return 2!=a.length?{name:"full_name",direction:"asc"}:{name:a[0],direction:a[1]}}},_sortAndLimitTasks:function(){swarming.stableSort(this._taskStats,this._compare.bind(this));var a=this._taskStats.length;return!this._show_all_tasks&&this._taskStats.length>t&&(a=t),this._taskStats.slice(0,a)},_sortChange:function(t){t&&t.detail&&t.detail.name&&(t.preventDefault(),t.stopPropagation(),this.set("_sortstr",t.detail.name+":"+t.detail.direction))}})}()</script> </dom-module><dom-module id="bot-page" assetpath="/res/imp/botpage/"> <template> <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style single-page-style task-style">.message{white-space:pre-line;font-family:monospace}.bot_state{white-space:pre;font-family:monospace;margin-bottom:10px}.events_table,.tasks_table{border:3px solid #1F78B4}.old_version{background-color:#ffd}.stats{min-width:700px;flex-grow:2}#collapse{max-width:700px}.cloud{white-space:nowrap;margin-bottom:5px;margin-top:auto}.deleted{text-align:center;font-size:larger}paper-checkbox{--paper-checkbox-label-color:#fff;--paper-checkbox-checked-color:#fff;--paper-checkbox-checkmark-color:#000;--paper-checkbox-unchecked-color:#fff;padding:3px}paper-dialog{border-radius:6px}</style> <url-param name="id" value="{{bot_id}}"> </url-param> <url-param name="show_all_events" value="{{_show_all}}"> </url-param> <url-param name="selected" value="{{_selected}}"> </url-param> <url-param name="show_state" value="{{_show_state}}"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,_busy2,_busy3)]]" name="Swarming Bot Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <bot-page-data id="data" auth_headers="[[_auth_headers]]" bot_id="[[bot_id]]" bot="{{_bot}}" bot_exists="{{_bot_exists}}" busy="{{_busy1}}" events="{{_events}}" tasks="{{_tasks}}" on-reload="_clearAndReload"> </bot-page-data> <div class="header horizontal layout"> <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></paper-input> <template is="dom-if" if="[[_ccLink(_bot)]]"> <div class="vertical layout"> <a href$="[[_ccLink(_bot)]]" class="cloud">Cloud Console</a> </div> </template> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> </div> </div> <h2 hidden$="[[_bot_exists]]">Bot not found.</h2> <div hidden$="[[_not(_bot_exists)]]"> <div class="horizontal wrap layout"> <div class="flex"> <table> <template is="dom-if" if="[[_bot.deleted]]"> <tr class="dead deleted" title="This bot was deleted."> <td colspan="3">THIS BOT WAS DELETED</td> </tr> </template> <tbody><tr class$="[[_isDead(_bot)]]" title="Last time the bot contacted the server."> <td>Last Seen</td> <td title="[[_bot.human_last_seen_ts]]"> [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> <td> <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> <button class="raised" on-click="_promptShutdown"> Shut Down Gracefully </button> </template> <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> <button class="raised" on-click="_promptDelete"> Delete </button> </template> </td> </tr> <template is="dom-if" if="[[_bot.quarantined]]"> <tr class="quarantined"> <td>Quarantined</td> <td colspan="2" class="message">[[_quarantineMessage(_bot)]]</td> </tr> </template> <tr> <td>Current Task</td> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(_bot.task_id)]]"> [[_task(_bot)]] </a> </td> <td> </td> </tr> <tr> <td rowspan$="[[_numRows(_bot.dimensions)]]"> <a href$="[[_siblingBotsLink(_bot.dimensions)]]" title="The list of bots that also matches these dimensions (except id)."> Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_bot.dimensions]]" as="dim"> <tr> <td>[[dim.key]]</td> <td>[[_concat(dim.value)]]</td> </tr> </template> <tr title="IP address that the server saw the connection from."> <td>External IP</td> <td><a href$="[[_bot.external_ip]]">[[_bot.external_ip]]</a></td> <td></td> </tr> <tr class$="[[_classVersion(_server_details.bot_version,_bot.version)]]" title="Version is based on the content of swarming_bot.zip which is the swarming bot code. The bot won't update if quarantined, dead, or busy."> <td>Bot Version</td> <td>[[_shorten(_bot.version,'8')]]</td> <td></td> </tr> <tr title="The version the server expects the bot to be using."> <td>Expected Bot Version</td> <td>[[_shorten(_server_details.bot_version,'8')]]</td> <td></td> </tr> <tr title="First time ever a bot with this id contacted the server."> <td>First seen</td> <td title="[[_bot.human_first_seen_ts]]"> [[_timeDiffApprox(_bot.first_seen_ts)]] ago </td> <td></td> </tr> <tr title="How the bot is authenticated by the server."> <td>Authenticated as</td> <td colspan="2">[[_bot.authenticated_as]]</td> </tr> <template is="dom-if" if="[[_bot.lease_id]]"> <tr> <td>Machine Provider Lease ID</td> <td colspan="2"> <a href$="[[_mpLink(_bot,_server_details.machine_provider_template)]]"> [[_bot.lease_id]] </a> </td> </tr> <tr> <td>Machine Provider Lease Expires</td> <td colspan="2">[[_bot.human_lease_expiration_ts]]</td> </tr> </template> </tbody></table> <span class="title">State</span> <template is="dom-if" if="[[_not(_show_state)]]"> <button on-click="_toggleState"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </template> <template is="dom-if" if="[[_show_state]]"> <button on-click="_toggleState"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </template> <iron-collapse id="collapse" opened="[[_show_state]]"> <div class="bot_state">[[_prettyPrint(_bot.state)]]</div> </iron-collapse> </div> <div class="stats flex"> <bot-page-summary tasks="[[_tasks]]"> </bot-page-summary> </div> </div> <div class="tabs"> <paper-tabs selected="{{_selected}}" no-bar=""> <paper-tab>Tasks</paper-tab> <paper-tab>Events</paper-tab> </paper-tabs> <template is="dom-if" if="[[_showEvents]]"> <paper-checkbox checked="{{_show_all}}"> Show all events </paper-checkbox> </template> </div> <template is="dom-if" if="[[_not(_showEvents)]]"> <table class="tasks_table"> <thead> <tr> <th>Task</th> <th>Started</th> <th>Duration</th> <th>Result</th> </tr> </thead> <tbody> <template is="dom-repeat" items="{{_tasks}}" as="task"> <tr class$="[[_taskClass(task)]]"> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(task.task_id)]]"> [[task.name]] </a> </td> <td>[[task.human_started_ts]]</td> <td title="[[task.human_completed_ts]]">[[task.human_duration]]</td> <td>[[task.state]]</td> </tr> </template> </tbody> </table> </template> <template is="dom-if" if="[[_showEvents]]"> <table class="events_table"> <thead> <tr> <th>Message</th> <th>Type</th> <th>Timestamp</th> <th>Task ID</th> <th>Version</th> </tr> </thead> <tbody> <template is="dom-repeat" items="{{_eventList(_show_all,_events.*)}}" as="event"> <tr> <td class="message">[[event.message]]</td> <td>[[event.event_type]]</td> <td>[[event.human_ts]]</td> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(event.task_id)]]"> [[event.task_id]] </a> </td> <td class$="[[_classVersion(_server_details.bot_version,event.version)]]"> [[_shorten(event.version,'8')]] </td> </tr> </template> </tbody> </table> </template> <pageable-data id="page_tasks" hidden$="[[_showEvents]]" busy="{{_busy2}}" label="Show more tasks" output="{{_tasks}}" parse="[[_parseTasks]]"> </pageable-data> <pageable-data id="page_events" hidden$="[[_not(_showEvents)]]" busy="{{_busy3}}" label="Show more events" output="{{_events}}" parse="[[_parseEvents]]"> </pageable-data> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialogPrompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> </template> <script> (function(){
|
| + })() </script> </dom-module><dom-module id="task-list" assetpath="/res/imp/tasklist/"> <template> <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style dynamic-table-style task-style">task-filters{margin-bottom:8px;margin-right:10px}.task-list th>span{padding-right:30px}</style> <url-param name="s" value="{{_sortstr}}" default_value="created_ts:desc"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,_busy2)]]" name="Swarming Task List"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-list-data id="data" auth_headers="[[_auth_headers]]" query_params="[[_query_params]]" tasks="[[_items]]" busy="{{_busy1)}}" dimensions="{{_dimensions}}" primary_map="{{_primary_map}}" primary_arr="{{_primary_arr}}"> </task-list-data> <div class="horizontal layout"> <task-filters dimensions="[[_dimensions]]" permissions="[[_permissions]]" primary_map="[[_primary_map]]" primary_arr="[[_primary_arr]]" special_columns="[[_specialColumns]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter}}" on-cancel-all="_promptCancelAll"> </task-filters> </div> <table class="task-list"> <thead on-sort_change="_sortChange"> <tr> <th> <span>Task Name</span> <sort-toggle name="name" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('state', _columns.*)]]"> <span>State</span> <sort-toggle name="state" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('bot', _columns.*)]]"> <span>Bot Assigned</span> <sort-toggle name="bot" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('deduped_from', _columns.*)]]"> <span>Deduped from</span> <sort-toggle name="deduped_from" current="[[_sort]]"> </sort-toggle> </th> <th hidden$="[[_hide('source_revision', _columns.*)]]"> <span>Source Revision</span> <sort-toggle name="source_revision" current="[[_sort]]"> </sort-toggle> </th> <template is="dom-repeat" items="[[_plainColumns]]" as="c"> <th hidden$="[[_hide(c)]]"> <span>[[_header(c)]]</span> <sort-toggle name="[[c]]" current="[[_sort]]"> </sort-toggle> </th> </template> </tr> </thead> <tbody> <template id="tasks_table" is="dom-repeat" items="[[_filteredSortedItems]]" as="task" initial-count="50"> <tr class$="[[_taskClass(task)]]"> <td> <a class="center" href$="[[_taskLink(task.task_id)]]" target="_blank"> [[task.name]] </a> </td> <td hidden$="[[_hide('state', _columns.*)]]"> [[_column('state', task)]] <paper-button raised="" hidden$="[[_cannotCancel(task,_permissions)]]" on-tap="_promptCancel"> Cancel </paper-button> </td> <td hidden$="[[_hide('bot', _columns.*)]]"> <a class="center" href$="[[_botLink(task.bot_id)]]" target="_blank"> [[_column('bot',task)]] </a> </td> <td hidden$="[[_hide('deduped_from', _columns.*)]]"> <a class="center" href$="[[_taskLink(task.deduped_from)]]" target="_blank"> [[_column('deduped_from',task)]] </a> </td> <td hidden$="[[_hide('source_revision', _columns.*)]]"> <a class="center" href$="[[_sourceLink(task)]]" target="_blank"> [[_column('source_revision',task)]] </a> </td> <template is="dom-repeat" items="[[_plainColumns]]" as="c"> <td hidden$="[[_hide(c)]]"> [[_column(c, task)]] </td> </template> </tr> </template> </tbody> </table> <pageable-data id="page_tasks" busy="{{_busy2}}" label="Show more tasks" output="{{_items}}" parse="[[_parseTasks]]"> </pageable-data> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialogPrompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <paper-dialog id="cancel_all_dialog" modal=""> <task-mass-cancel id="mass_cancel" auth_headers="[[_auth_headers]]" started_canceling="{{_started_canceling}}" finished_canceling="{{_finished_canceling}}"> </task-mass-cancel> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="" hidden$="[[_started_canceling]]"> Go Back - Don't Cancel Anything </paper-button> <paper-button dialog-dismiss="" autofocus="" hidden$="[[!_finished_canceling]]"> Done </paper-button> </div> </paper-dialog> </template> <script>!function(){function t(t){return function(e){return this._attribute(e,"human_"+t)[0]}}function e(t){return function(e,a,s){var n=this._attribute(a,t,"0")[0],i=this._attribute(s,t,"0")[0];return e*(n-i)}}var a=["deduped_from","name","state","bot","source_revision"],s={abandoned_ts:t("abandoned_ts"),bot:function(t){return this._attribute(t,"bot_id")[0]},completed_ts:t("completed_ts"),costs_usd:function(t){return this._attribute(t,"costs_usd",0)[0]},created_ts:t("created_ts"),duration:t("duration"),modified_ts:t("modified_ts"),source_revision:function(t){var e=this._attribute(t,"source_revision")[0];return e.substring(0,8)},started_ts:t("started_ts"),state:function(t){var e=this._attribute(t,"state")[0];if("COMPLETED"===e){if(this._attribute(t,"failure",!1)[0])return"COMPLETED (FAILURE)";var a=this._attribute(t,"try_number","-1")[0];return"0"===a?"COMPLETED (DEDUPED)":"COMPLETED (SUCCESS)"}return e}},n={abandoned_ts:"Abandoned On",completed_ts:"Completed On",created_ts:"Created On",duration:"Duration",modified_ts:"Last Modified",started_ts:"Started Working On",user:"Requesting User"},i={abandoned_ts:e("abandoned_ts"),completed_ts:e("completed_ts"),created_ts:e("created_ts"),duration:e("duration"),modified_ts:e("modified_ts"),started_ts:e("started_ts")};Polymer({is:"task-list",behaviors:[SwarmingBehaviors.DynamicTableBehavior,SwarmingBehaviors.TaskBehavior],properties:{client_id:{type:String},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_parseTasks:{type:Function,value:function(){return this.$.data.parseTasks.bind(this)}},_toCancel:{type:String},_columnMap:{type:Object,value:function(){var t=this._commonColumns();for(var e in s)t[e]=s[e];return t}},_headerMap:{type:Object,value:n},_specialColumns:{type:Array,value:a},_specialSort:{type:Object,value:i}},observers:["reload(_query_params,_auth_headers)"],_attribute:function(t,e,a){void 0===a&&(a="none");var s=this._tag(t,e)||t[e]||[a];return Array.isArray(s)?s:[s]},_cannotCancel:function(t,e){return!(e&&e.cancel_task&&"PENDING"===this._column("state",t))},_cancelTask:function(){var t="/api/swarming/v1/task/"+this._toCancel+"/cancel";swarming.postWithToast(t,"Canceling task "+this._toCancel,this._auth_headers),this.set("_toCancel","")},_promptClosed:function(t){t.detail.confirmed&&this._cancelTask()},_promptCancel:function(t){var e=t.model.task;return e&&e.task_id?(this.set("_toCancel",e.task_id),this.set("_dialogPrompt",'cancel task "'+e.name+'"'),void this.$.prompt.open()):void console.log("Missing task info",e)},_promptCancelAll:function(t){this.$.mass_cancel.tags=t.detail.tags,this.$.mass_cancel.prompt(),this.$.cancel_all_dialog.open()},_closeCancelAll:function(){this.$.cancel_all_dialog.close()},reload:function(){if(this._auth_headers&&this._query_params){var t="/api/swarming/v1/tasks/list?"+sk.query.fromParamSet(this._query_params);this.$.page_tasks.load(t,this._auth_headers)}},_sourceLink:function(t){var e=this._attribute(t,"source_revision")[0],a=this._attribute(t,"source_repo")[0];return"none"!==e&&"none"!==a&&a.replace("%s",e)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_taskClass:function(t){return this.stateClass(this._column("state",t))}})}()</script> </dom-module> <dom-module id="iron-collapse" assetpath="/res/imp/bower_components/iron-collapse/"> <template> <style>:host{display:block;transition-duration:var(--iron-collapse-transition-duration,300ms);overflow:visible}:host(.iron-collapse-closed){display:none}:host(:not(.iron-collapse-opened)){overflow:hidden}</style> <content></content> </template> </dom-module> <script>Polymer({is:"iron-collapse",behaviors:[Polymer.IronResizableBehavior],properties:{horizontal:{type:Boolean,value:!1,observer:"_horizontalChanged"},opened:{type:Boolean,value:!1,notify:!0,observer:"_openedChanged"},noAnimation:{type:Boolean},_desiredSize:{type:String,value:""}},get dimension(){return this.horizontal?"width":"height"},get _dimensionMax(){return this.horizontal?"maxWidth":"maxHeight"},get _dimensionMaxCss(){return this.horizontal?"max-width":"max-height"},hostAttributes:{role:"group","aria-hidden":"true","aria-expanded":"false"},listeners:{transitionend:"_transitionEnd"},attached:function(){this._transitionEnd()},toggle:function(){this.opened=!this.opened},show:function(){this.opened=!0},hide:function(){this.opened=!1},updateSize:function(i,t){if(i="auto"===i?"":i,this._desiredSize!==i){this._desiredSize=i,this._updateTransition(!1);var e=t&&!this.noAnimation&&this._isDisplayed;if(e){var n=this._calcSize();""===i&&(this.style[this._dimensionMax]="",i=this._calcSize()),this.style[this._dimensionMax]=n,this.scrollTop=this.scrollTop,this._updateTransition(!0),e=i!==n}this.style[this._dimensionMax]=i,e||this._transitionEnd()}},enableTransition:function(i){Polymer.Base._warn("`enableTransition()` is deprecated, use `noAnimation` instead."),this.noAnimation=!i},_updateTransition:function(i){this.style.transitionDuration=i&&!this.noAnimation?"":"0s"},_horizontalChanged:function(){this.style.transitionProperty=this._dimensionMaxCss;var i="maxWidth"===this._dimensionMax?"maxHeight":"maxWidth";this.style[i]="",this.updateSize(this.opened?"auto":"0px",!1)},_openedChanged:function(){this.setAttribute("aria-expanded",this.opened),this.setAttribute("aria-hidden",!this.opened),this.toggleClass("iron-collapse-closed",!1),this.toggleClass("iron-collapse-opened",!1),this.updateSize(this.opened?"auto":"0px",!0),this.opened&&this.focus()},_transitionEnd:function(){this.style[this._dimensionMax]=this._desiredSize,this.toggleClass("iron-collapse-closed",!this.opened),this.toggleClass("iron-collapse-opened",this.opened),this._updateTransition(!1),this.notifyResize()},get _isDisplayed(){var i=this.getBoundingClientRect();for(var t in i)if(0!==i[t])return!0;return!1},_calcSize:function(){return this.getBoundingClientRect()[this.dimension]+"px"}})</script> <script>Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(e){this.focusedItem.click(),e.detail.keyboardEvent.preventDefault()},_onDownKey:function(e){this.focusedItem.click(),e.detail.keyboardEvent.preventDefault()},get _isRTL(){return"rtl"===window.getComputedStyle(this).direction},_onLeftKey:function(e){this._isRTL?this._focusNext():this._focusPrevious(),e.detail.keyboardEvent.preventDefault()},_onRightKey:function(e){this._isRTL?this._focusPrevious():this._focusNext(),e.detail.keyboardEvent.preventDefault()},_onKeydown:function(e){this.keyboardEventMatchesKeys(e,"up down left right esc")||this._focusWithKeyboardEvent(e)}},Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl]</script> <iron-iconset-svg name="paper-tabs" size="24"> <svg><defs> <g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path></g> <g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></g> </defs></svg> </iron-iconset-svg> <dom-module id="paper-tab" assetpath="/res/imp/bower_components/paper-tabs/"> <template> <style>:host{@apply(--layout-inline);@apply(--layout-center);@apply(--layout-center-justified);@apply(--layout-flex-auto);position:relative;padding:0 12px;overflow:hidden;cursor:pointer;vertical-align:middle;@apply(--paper-font-common-base);@apply(--paper-tab)}:host(:focus){outline:0}:host([link]){padding:0}.tab-content{height:100%;transform:translateZ(0);-webkit-transform:translateZ(0);transition:opacity .1s cubic-bezier(.4,0,1,1);@apply(--layout-horizontal);@apply(--layout-center-center);@apply(--layout-flex-auto);@apply(--paper-tab-content)}:host(:not(.iron-selected))>.tab-content{opacity:.8;@apply(--paper-tab-content-unselected)}:host(:focus) .tab-content{opacity:1;font-weight:700}paper-ripple{color:var(--paper-tab-ink,--paper-yellow-a100)}.tab-content>::content>a{@apply(--layout-flex-auto);height:100%}</style> <div class="tab-content"> <content></content> </div> </template> <script>Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:!1,reflectToAttribute:!0}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var t=Polymer.dom(this).parentNode;return!!t&&!!t.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(t){if(this.link){var e=this.queryEffectiveChildren("a");if(!e)return;if(t.target===e)return;e.click()}}})</script> </dom-module> <dom-module id="paper-tabs" assetpath="/res/imp/bower_components/paper-tabs/"> <template> <style>:host{@apply(--layout);@apply(--layout-center);height:48px;font-size:14px;font-weight:500;overflow:hidden;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:transparent;@apply(--paper-tabs)}:host-context([dir=rtl]){@apply(--layout-horizontal-reverse)}#tabsContainer{position:relative;height:100%;white-space:nowrap;overflow:hidden;@apply(--layout-flex-auto)}#tabsContent{height:100%;-moz-flex-basis:auto;-ms-flex-basis:auto;flex-basis:auto}#tabsContent.scrollable{position:absolute;white-space:nowrap}#tabsContent.scrollable.fit-container,#tabsContent:not(.scrollable){@apply(--layout-horizontal)}#tabsContent.scrollable.fit-container{min-width:100%}#tabsContent.scrollable.fit-container>::content>*{-ms-flex:1 0 auto;-webkit-flex:1 0 auto;flex:1 0 auto}.hidden{display:none}.not-visible{opacity:0;cursor:default}paper-icon-button{width:48px;height:48px;padding:12px;margin:0 4px}#selectionBar{position:absolute;height:2px;bottom:0;left:0;right:0;background-color:var(--paper-tabs-selection-bar-color,--paper-yellow-a100);-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:left center;transform-origin:left center;transition:-webkit-transform;transition:transform;@apply(--paper-tabs-selection-bar)}#selectionBar.align-bottom{top:0;bottom:auto}#selectionBar.expand{transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,1,1)}#selectionBar.contract{transition-duration:.18s;transition-timing-function:cubic-bezier(0,0,.2,1)}#tabsContent>::content>:not(#selectionBar){height:100%}</style> <paper-icon-button icon="paper-tabs:chevron-left" class$="[[_computeScrollButtonClass(_leftHidden, scrollable, hideScrollButtons)]]" on-up="_onScrollButtonUp" on-down="_onLeftScrollButtonDown" tabindex="-1"></paper-icon-button> <div id="tabsContainer" on-track="_scroll" on-down="_down"> <div id="tabsContent" class$="[[_computeTabsContentClass(scrollable, fitContainer)]]"> <div id="selectionBar" class$="[[_computeSelectionBarClass(noBar, alignBottom)]]" on-transitionend="_onBarTransitionEnd"></div> <content select="*"></content> </div> </div> <paper-icon-button icon="paper-tabs:chevron-right" class$="[[_computeScrollButtonClass(_rightHidden, scrollable, hideScrollButtons)]]" on-up="_onScrollButtonUp" on-down="_onRightScrollButtonDown" tabindex="-1"></paper-icon-button> </template> <script>Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:!1,observer:"_noinkChanged"},noBar:{type:Boolean,value:!1},noSlide:{type:Boolean,value:!1},scrollable:{type:Boolean,value:!1},fitContainer:{type:Boolean,value:!1},disableDrag:{type:Boolean,value:!1},hideScrollButtons:{type:Boolean,value:!1},alignBottom:{type:Boolean,value:!1},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:!1},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:!1},_rightHidden:{type:Boolean,value:!1},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null,this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0,this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this),this.addEventListener("blur",this._onBlurCapture.bind(this),!0)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(t){var e=Polymer.dom(this).querySelectorAll("paper-tab");e.forEach(t?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(t){t.setAttribute("noink","")},_removeNoinkAttribute:function(t){t.removeAttribute("noink")},_computeScrollButtonClass:function(t,e,i){return!e||i?"hidden":t?"not-visible":""},_computeTabsContentClass:function(t,e){return t?"scrollable"+(e?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(t,e){return t?"hidden":e?"align-bottom":""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll(),this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(t){this._tabChanged(t.detail.item,this._previousTab),this._previousTab=t.detail.item,this.cancelDebouncer("tab-changed")},_onIronDeselect:function(t){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab),this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation(),Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(t,e){this._pendingActivationItem=t,this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,e)},_delayedActivationHandler:function(){var t=this._pendingActivationItem;this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0,t.fire(this.activateEvent,null,{bubbles:!0,cancelable:!0})},_cancelPendingActivation:function(){void 0!==this._pendingActivationTimeout&&(this.cancelAsync(this._pendingActivationTimeout),this._pendingActivationItem=void 0,this._pendingActivationTimeout=void 0)},_onArrowKeyup:function(t){this.autoselect&&this._scheduleActivation(this.focusedItem,this.autoselectDelay)},_onBlurCapture:function(t){t.target===this._pendingActivationItem&&this._cancelPendingActivation()},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(t,e){if(this.scrollable){var i=e&&-e.ddx||0;this._affectScroll(i)}},_down:function(t){this.async(function(){this._defaultFocusAsync&&(this.cancelAsync(this._defaultFocusAsync),this._defaultFocusAsync=null)},1)},_affectScroll:function(t){this.$.tabsContainer.scrollLeft+=t;var e=this.$.tabsContainer.scrollLeft;this._leftHidden=0===e,this._rightHidden=e===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft(),this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight(),this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob),this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(t,e){if(!t)return this.$.selectionBar.classList.remove("expand"),this.$.selectionBar.classList.remove("contract"),void this._positionBar(0,0);var i=this.$.tabsContent.getBoundingClientRect(),n=i.width,o=t.getBoundingClientRect(),s=o.left-i.left;if(this._pos={width:this._calcPercent(o.width,n),left:this._calcPercent(s,n)},this.noSlide||null==e)return this.$.selectionBar.classList.remove("expand"),this.$.selectionBar.classList.remove("contract"),void this._positionBar(this._pos.width,this._pos.left);var a=e.getBoundingClientRect(),l=this.items.indexOf(e),c=this.items.indexOf(t),r=5;this.$.selectionBar.classList.add("expand");var h=l<c,d=this._isRTL;d&&(h=!h),h?this._positionBar(this._calcPercent(o.left+o.width-a.left,n)-r,this._left):this._positionBar(this._calcPercent(a.left+a.width-o.left,n)-r,this._calcPercent(s,n)+r),this.scrollable&&this._scrollToSelectedIfNeeded(o.width,s)},_scrollToSelectedIfNeeded:function(t,e){var i=e-this.$.tabsContainer.scrollLeft;i<0?this.$.tabsContainer.scrollLeft+=i:(i+=t-this.$.tabsContainer.offsetWidth,i>0&&(this.$.tabsContainer.scrollLeft+=i))},_calcPercent:function(t,e){return 100*t/e},_positionBar:function(t,e){t=t||0,e=e||0,this._width=t,this._left=e,this.transform("translateX("+e+"%) scaleX("+t/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(t){var e=this.$.selectionBar.classList;e.contains("expand")?(e.remove("expand"),e.add("contract"),this._positionBar(this._pos.width,this._pos.left)):e.contains("contract")&&e.remove("contract")}})</script> </dom-module> <dom-module id="single-page-style" assetpath="/res/imp/common/"> <template> <style>.header{max-width:800px}.title{font-size:1.5em;font-weight:700;margin:5px}.id_input{margin-left:5px;--paper-input-container-input:{font-size:2em};}.refresh{max-width:40px;max-height:40px;width:initial;height:initial}button{min-width:4em;max-height:55px}table{border-collapse:collapse;margin-left:5px;margin-bottom:8px}td,th{border:1px solid #BBB;padding:5px}.tabs{background-color:#1F78B4;color:#fff;max-width:600px;margin-left:5px;--paper-checkbox-label-color:#fff}paper-tab{background-color:#A6CEE3;color:#000}paper-tab.iron-selected{background-color:#1F78B4;color:#fff;font-weight:700;text-decoration:underline}paper-tab[disabled]{background-color:#AAA;text-decoration:line-through}.quarantined{background-color:#fdd}.dead{background-color:#ccc}paper-checkbox{--paper-checkbox-checked-color:#1F78B4}</style> </template> </dom-module><script>!function(){SwarmingBehaviors.BotPageBehavior=[SwarmingBehaviors.CommonBehavior,{}]}()</script> <dom-module id="bot-page-data" assetpath="/res/imp/botpage/"> <script>!function(){function t(t){if(!s){var e=t.toString();s=e.substring(e.indexOf("("))}return t.toLocaleString()+" "+s}var e,s,i=400,n=["first_seen_ts","last_seen_ts","lease_expiration_ts"],a=["started_ts","completed_ts","abandoned_ts","modified_ts"];Polymer({is:"bot-page-data",behaviors:[SwarmingBehaviors.BotPageBehavior],properties:{auth_headers:{type:Object},bot_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1)",notify:!0},bot:{type:Object,computed:"_parseBot(_bot)",notify:!0},bot_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_bot:{type:Object},_events:{type:Object},_tasks:{type:Object}},observers:["request(auth_headers,bot_id)"],request:function(){this.bot_id&&this.auth_headers&&(e&&this.cancelAsync(e),e=this.async(function(){e=void 0;var t="/api/swarming/v1/bot/"+this.bot_id,s=this._getJsonAsync("_bot",t+"/get","_busy1",this.auth_headers);s.then(function(){this.set("bot_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("bot_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this.fire("reload",{id:this.bot_id})},i))},_parseBot:function(e){if(!e)return{};e.state=e.state||"{}",e.state=JSON.parse(e.state)||{};var s=e.state.disks||{},i=Object.keys(s);if(i.length){e.disks=[];for(var a=0;a<i.length;a++)e.disks.push({id:i[a],mb:s[i[a]].free_mb});e.disks.sort(function(t,e){return e.mb-t.mb})}else e.disks=[{id:"unknown",mb:0}];return e.dimensions=e.dimensions||[],e.dimensions.forEach(function(t){swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(t.key)!==-1&&t.value.forEach(function(e,s){t.value[s]=swarming.alias.apply(e,t.key)})}),n.forEach(function(s){e[s]&&(e[s]=new Date(e[s]),e["human_"+s]=t(e[s]))}),e},parseEvents:function(e){if(!e||!e.items)return[];var e=e.items;return e.forEach(function(e){e.ts&&(e.ts=new Date(e.ts),e.human_ts=t(e.ts))}),e.sort(function(t,e){return e.ts-t.ts}),e},parseTasks:function(e){if(!e||!e.items)return[];var e=e.items;return e.forEach(function(e){if(a.forEach(function(s){e[s]&&(e[s]=new Date(e[s]),e["human_"+s]=t(e[s]))}),e.duration)e.human_duration=this._humanDuration(e.duration);else{var s=e.completed_ts||e.abandoned_ts||e.modified_ts||new Date;e.human_duration=this._timeDiffExact(e.started_ts,s),e.duration=(s.getTime()-e.started_ts)/1e3}e.state=e.state||"UNKNOWN","COMPLETED"===e.state&&(e.failure?e.state="FAILURE":e.state="SUCCESS")}.bind(this)),e.sort(function(t,e){return e.started_ts-t.started_ts}),e}})}()</script> </dom-module> <dom-module id="bot-page-summary" assetpath="/res/imp/botpage/"> <template> <style include="single-page-style">.wrapper{display:table;margin-left:auto;margin-bottom:10px;margin-right:5px}paper-checkbox{margin-left:5px}.thick{border-top-style:solid}</style> <url-param name="show_full_names" value="{{_show_full_names}}"> </url-param> <url-param name="show_all_tasks" value="{{_show_all_tasks}}"> </url-param> <url-param name="sort_stats" value="{{_sortstr}}" default_value="total:desc"> </url-param> <div class="wrapper"> <table> <thead on-sort_change="_sortChange"> <tr> <th> <span>Name</span> <sort-toggle name="full_name" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Total</span> <sort-toggle name="total" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Success</span> <sort-toggle name="success" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Failed</span> <sort-toggle name="failed" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Died</span> <sort-toggle name="bot_died" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Average Duration</span> <sort-toggle name="avg_duration" current="[[_sort]]"> </sort-toggle> </th> <th> <span>Total Duration</span> <sort-toggle name="total_time" current="[[_sort]]"> </sort-toggle> </th> <th>Percent of Total</th> </tr> </thead> <tbody> <template is="dom-repeat" items="[[_tasksToShow]]" as="task"> <tr> <td hidden$="[[_truthy(_show_full_names)]]" title="[[task.full_name]]">[[task.name]]</td> <td hidden$="[[_not(_show_full_names)]]" title="[[task.full_name]]">[[task.full_name]]</td> <td>[[task.total]]</td> <td>[[task.success]]</td> <td>[[task.failed]]</td> <td>[[task.bot_died]]</td> <td>[[_humanDuration(task.avg_duration)]]</td> <td>[[_humanDuration(task.total_time)]]</td> <td>[[task.total_time_percent]]%</td> </tr> </template> </tbody> <tbody><tr class="thick"> <td>Total</td> <td>[[_totalStats.total]]</td> <td>[[_totalStats.success]]</td> <td>[[_totalStats.failed]]</td> <td>[[_totalStats.bot_died]]</td> <td>[[_humanDuration(_totalStats.avg_duration)]]</td> <td>[[_humanDuration(_totalStats.total_time)]]</td> <td>100.0%</td> </tr> </tbody></table> <div> <table> <thead> <tr> <th title="How much time passed between the oldest task fetched and now."> Total Wall Time </th> <th title="How much of the wall time this bot was busy with a task."> Wall Time Utilization </th> </tr> </thead> <tbody> <tr> <td>[[_humanDuration(_totalStats.wall_time)]]</td> <td>[[_totalStats.wall_time_utilization]]%</td> </tr> </tbody> </table> <paper-checkbox checked="{{_show_full_names}}"> Show Full Names </paper-checkbox> <paper-checkbox hidden$="[[_cannotExpand]]" checked="{{_show_all_tasks}}"> Show All Tasks </paper-checkbox> </div> </div> </template> <script>!function(){var t=15;Polymer({is:"bot-page-summary",behaviors:[SwarmingBehaviors.BotPageBehavior],properties:{tasks:{type:Array},_cannotExpand:{type:Boolean,computed:"_countTasks(_taskStats.*)"},_show_all_tasks:{type:Boolean},_show_full_names:{type:Boolean},_sortstr:{type:String},_sort:{type:Object,computed:"_makeSortObject(_sortstr)"},_taskStats:{type:Array},_tasksToShow:{type:Array,computed:"_sortAndLimitTasks(_taskStats.*,_sort.*,_show_all_tasks)"},_totalStats:{type:Object}},observers:["_aggregate(tasks.*)"],_aggregate:function(){if(this.tasks&&this.tasks.length){var t=new Date(1e3*sk.now()),a={},e={total:this.tasks.length,success:0,failed:0,bot_died:0,avg_duration:0,total_time:0,wall_time:(t-this.tasks[this.tasks.length-1].started_ts)/1e3};this.tasks.forEach(function(t){var s=t.name.trim(),i=s.split("/");5===i.length&&(s=i[0]+"/"+i[3]),a[s]||(a[s]={full_name:s,name:s,total:0,success:0,failed:0,bot_died:0,avg_duration:0,total_time:0}),a[s].total++,t.failure?(e.failed++,a[s].failed++):t.internal_failure?(e.bot_died++,a[s].bot_died++):(e.success++,a[s].success++),e.total_time+=t.duration,a[s].total_time+=t.duration}),e.avg_duration=e.total_time/e.total,e.wall_time_utilization=(100*e.total_time/e.wall_time).toFixed(1),this.set("_totalStats",e);var s=Object.keys(a),i=[];s.forEach(function(t){a[t].avg_duration=a[t].total_time/a[t].total,a[t].total_time_percent=(100*a[t].total_time/e.total_time).toFixed(1),i.push(a[t])});var o=new Substrings({minOccurrence:Math.max(2,s.length-1),minLength:6});o.build(s);var n=o.weighByAverage()||[];n.length&&n[0].source.forEach(function(t){var a=i[t].full_name;i[t].name=a.replace(n[0].name,"...")}),this.set("_taskStats",i)}},_compare:function(t,a){if(!this._sort)return 0;var e=1;return"desc"===this._sort.direction&&(e=-1),e*swarming.naturalCompare(t[this._sort.name],a[this._sort.name])},_countTasks:function(){return this._taskStats.length<=t},_makeSortObject:function(t){if(t){var a=t.split(":");return 2!=a.length?{name:"full_name",direction:"asc"}:{name:a[0],direction:a[1]}}},_sortAndLimitTasks:function(){swarming.stableSort(this._taskStats,this._compare.bind(this));var a=this._taskStats.length;return!this._show_all_tasks&&this._taskStats.length>t&&(a=t),this._taskStats.slice(0,a)},_sortChange:function(t){t&&t.detail&&t.detail.name&&(t.preventDefault(),t.stopPropagation(),this.set("_sortstr",t.detail.name+":"+t.detail.direction))}})}()</script> </dom-module><dom-module id="bot-page" assetpath="/res/imp/botpage/"> <template> <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style single-page-style task-style">.message{white-space:pre-line;font-family:monospace}.bot_state{white-space:pre;font-family:monospace;margin-bottom:10px}.events_table,.tasks_table{border:3px solid #1F78B4}.old_version{background-color:#ffd}.stats{min-width:700px;flex-grow:2}#collapse{max-width:700px}.cloud{white-space:nowrap;margin-bottom:5px;margin-top:auto}.deleted{text-align:center;font-size:larger}paper-dialog{border-radius:6px}</style> <url-param name="id" value="{{bot_id}}"> </url-param> <url-param name="show_all_events" value="{{_show_all}}"> </url-param> <url-param name="selected" value="{{_selected}}"> </url-param> <url-param name="show_state" value="{{_show_state}}"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,_busy2,_busy3)]]" name="Swarming Bot Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <bot-page-data id="data" auth_headers="[[_auth_headers]]" bot_id="[[bot_id]]" bot="{{_bot}}" bot_exists="{{_bot_exists}}" busy="{{_busy1}}" events="{{_events}}" tasks="{{_tasks}}" on-reload="_clearAndReload"> </bot-page-data> <div class="header horizontal layout"> <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></paper-input> <template is="dom-if" if="[[_ccLink(_bot)]]"> <div class="vertical layout"> <a href$="[[_ccLink(_bot)]]" class="cloud">Cloud Console</a> </div> </template> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> </div> </div> <h2 hidden$="[[_bot_exists]]">Bot not found.</h2> <div hidden$="[[_not(_bot_exists)]]"> <div class="horizontal wrap layout"> <div class="flex"> <table> <template is="dom-if" if="[[_bot.deleted]]"> <tr class="dead deleted" title="This bot was deleted."> <td colspan="3">THIS BOT WAS DELETED</td> </tr> </template> <tbody><tr class$="[[_isDead(_bot)]]" title="Last time the bot contacted the server."> <td>Last Seen</td> <td title="[[_bot.human_last_seen_ts]]"> [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> <td> <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> <button class="raised" on-click="_promptShutdown"> Shut Down Gracefully </button> </template> <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> <button class="raised" on-click="_promptDelete"> Delete </button> </template> </td> </tr> <template is="dom-if" if="[[_bot.quarantined]]"> <tr class="quarantined"> <td>Quarantined</td> <td colspan="2" class="message">[[_quarantineMessage(_bot)]]</td> </tr> </template> <tr> <td>Current Task</td> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(_bot.task_id)]]"> [[_task(_bot)]] </a> </td> <td> </td> </tr> <tr> <td rowspan$="[[_numRows(_bot.dimensions)]]"> <a href$="[[_siblingBotsLink(_bot.dimensions)]]" title="The list of bots that also matches these dimensions (except id)."> Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_bot.dimensions]]" as="dim"> <tr> <td>[[dim.key]]</td> <td>[[_concat(dim.value)]]</td> </tr> </template> <tr title="IP address that the server saw the connection from."> <td>External IP</td> <td><a href$="[[_bot.external_ip]]">[[_bot.external_ip]]</a></td> <td></td> </tr> <tr class$="[[_classVersion(_server_details.bot_version,_bot.version)]]" title="Version is based on the content of swarming_bot.zip which is the swarming bot code. The bot won't update if quarantined, dead, or busy."> <td>Bot Version</td> <td>[[_shorten(_bot.version,'8')]]</td> <td></td> </tr> <tr title="The version the server expects the bot to be using."> <td>Expected Bot Version</td> <td>[[_shorten(_server_details.bot_version,'8')]]</td> <td></td> </tr> <tr title="First time ever a bot with this id contacted the server."> <td>First seen</td> <td title="[[_bot.human_first_seen_ts]]"> [[_timeDiffApprox(_bot.first_seen_ts)]] ago </td> <td></td> </tr> <tr title="How the bot is authenticated by the server."> <td>Authenticated as</td> <td colspan="2">[[_bot.authenticated_as]]</td> </tr> <template is="dom-if" if="[[_bot.lease_id]]"> <tr> <td>Machine Provider Lease ID</td> <td colspan="2"> <a href$="[[_mpLink(_bot,_server_details.machine_provider_template)]]"> [[_bot.lease_id]] </a> </td> </tr> <tr> <td>Machine Provider Lease Expires</td> <td colspan="2">[[_bot.human_lease_expiration_ts]]</td> </tr> </template> </tbody></table> <span class="title">State</span> <template is="dom-if" if="[[_not(_show_state)]]"> <button on-click="_toggleState"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </template> <template is="dom-if" if="[[_show_state]]"> <button on-click="_toggleState"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </template> <iron-collapse id="collapse" opened="[[_show_state]]"> <div class="bot_state">[[_prettyPrint(_bot.state)]]</div> </iron-collapse> </div> <div class="stats flex"> <bot-page-summary tasks="[[_tasks]]"> </bot-page-summary> </div> </div> <div class="tabs"> <paper-tabs selected="{{_selected}}" no-bar=""> <paper-tab>Tasks</paper-tab> <paper-tab>Events</paper-tab> </paper-tabs> <template is="dom-if" if="[[_showEvents]]"> <paper-checkbox checked="{{_show_all}}"> Show all events </paper-checkbox> </template> </div> <template is="dom-if" if="[[_not(_showEvents)]]"> <table class="tasks_table"> <thead> <tr> <th>Task</th> <th>Started</th> <th>Duration</th> <th>Result</th> </tr> </thead> <tbody> <template is="dom-repeat" items="{{_tasks}}" as="task"> <tr class$="[[_taskClass(task)]]"> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(task.task_id)]]"> [[task.name]] </a> </td> <td>[[task.human_started_ts]]</td> <td title="[[task.human_completed_ts]]">[[task.human_duration]]</td> <td>[[task.state]]</td> </tr> </template> </tbody> </table> </template> <template is="dom-if" if="[[_showEvents]]"> <table class="events_table"> <thead> <tr> <th>Message</th> <th>Type</th> <th>Timestamp</th> <th>Task ID</th> <th>Version</th> </tr> </thead> <tbody> <template is="dom-repeat" items="{{_eventList(_show_all,_events.*)}}" as="event"> <tr> <td class="message">[[event.message]]</td> <td>[[event.event_type]]</td> <td>[[event.human_ts]]</td> <td> <a target="_blank" rel="noopener" href$="[[_taskLink(event.task_id)]]"> [[event.task_id]] </a> </td> <td class$="[[_classVersion(_server_details.bot_version,event.version)]]"> [[_shorten(event.version,'8')]] </td> </tr> </template> </tbody> </table> </template> <pageable-data id="page_tasks" hidden$="[[_showEvents]]" busy="{{_busy2}}" label="Show more tasks" output="{{_tasks}}" parse="[[_parseTasks]]"> </pageable-data> <pageable-data id="page_events" hidden$="[[_not(_showEvents)]]" busy="{{_busy3}}" label="Show more events" output="{{_events}}" parse="[[_parseEvents]]"> </pageable-data> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialogPrompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> </template> <script> (function(){
|
|
|
| Polymer({
|
| is: 'bot-page',
|
| @@ -1132,4 +1132,4 @@ the fleet."> <template is="dom-repeat" items="[[_filters]]" as="fil"> <div class
|
| }
|
|
|
| });
|
| - })(); </script> </dom-module><dom-module id="interval-timer" assetpath="/res/imp/common/"> <script>!function(){Polymer({is:"interval-timer",properties:{period:{type:Number,value:-1,observer:"_periodChanged"}},_periodChanged:function(e){this._timeout&&window.clearTimeout(this._timeout),e>0&&(this._timeout=window.setTimeout(function(){this.fire("trigger"),this._periodChanged(e)}.bind(this),1e3*e))}})}()</script> </dom-module> <dom-module id="task-page-data" assetpath="/res/imp/taskpage/"> <script>!function(){var t,e=400,s=["abandoned_ts","completed_ts","created_ts","modified_ts","started_ts"];Polymer({is:"task-page-data",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},task_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1,_busy2,_busy3)",notify:!0},request:{type:Object,computed:"_parseRequest(_request)",notify:!0},result:{type:Object,computed:"_parseResult(_result)",notify:!0},stdout:{type:String,computed:"_parseStdout(_stdout)",notify:!0},task_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_busy3:{type:Boolean,value:!1},_request:{type:Object},_result:{type:Object},_stdout:{type:Object}},observers:["reload(auth_headers,task_id)"],reload:function(){if(!this.task_id||!this.auth_headers)return void console.log("task_id and auth_headers can't be empty");t&&this.cancelAsync(t);var s="/api/swarming/v1/task/"+this.task_id;t=this.async(function(){t=void 0;var e=this._getJsonAsync("_request",s+"/request","_busy1",this.auth_headers);e.then(function(){this.set("task_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("task_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this._getJsonAsync("_result",s+"/result?include_performance_stats=true","_busy2",this.auth_headers),this.reloadStdout()},e)},_parseRequest:function(t){return t?(t.tagMap={},t.tags=t.tags||[],t.tags.forEach(function(e){var s=e.split(":",1),a=s[0],u=e.substring(a.length+1);t.tagMap[a]=u}),s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),t):{}},_parseResult:function(t){if(!t)return{};var e=new Date;return s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),!t.duration&&t.state===this.RUNNING&&t.started_ts&&(t.duration=(e-t.started_ts)/1e3),t.duration&&(t.human_duration=this._humanDuration(t.duration)),t},_parseStdout:function(t){return t&&t.output?t.output:""},reloadStdout:function(){this._getJsonAsync("_stdout","/api/swarming/v1/task/"+this.task_id+"/stdout","_busy3",this.auth_headers)}})}()</script> </dom-module><dom-module id="task-disambiguation" assetpath="/res/imp/taskpage/"> <template> <style include="swarming-app-style single-page-style task-style"></style> <table> <thead> <tr> <th>Try ID</th> <th>Bot ID</th> <th>Status</th> </tr> </thead> <tbody> <template id="result_list" is="dom-repeat" items="[[_results]]" as="result" observe="task_id bot_id state"> <tr> <td> <a href$="[[_taskLink(result.task_id,'true')]]"> [[result.task_id]] </a> </td> <td> <a href$="[[_botLink(result.bot_id)]]"> [[result.bot_id]] </a> </td> <td class$="[[_stateClass(result)]]">[[state(result)]]</td> </tr> </template> </tbody> </table> </template> <script>Polymer({is:"task-disambiguation",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},summary_result:{type:Object},task_id:{type:String},busy:{type:Boolean,value:!1,notify:!0},_busyArr:{type:Array,value:function(){return[]}},_results:{type:Array,value:function(){return[]}}},observers:["_fetchRest(auth_headers,task_id,summary_result)","_computeBusy(_busyArr.*)"],_computeBusy:function(){for(var s=0;s<this._busyArr.length;s++)if(this._busyArr[s].status)return!0;return!1},_fetchRest:function(s,r,t){if(s&&r&&t){var e=t.try_number;this.set("_busyArr",[]),this.set("_results",[]);for(var u=r.substring(0,r.length-1),i="/api/swarming/v1/task/",a=0;a<e-1;a++){var n=u+(a+1);this.splice("_busyArr",a,0,{}),this.splice("_results",a,0,{task_id:n}),this._getJsonAsyncArr(a,"_results",i+n+"/result","_busyArr",s)}t.task_id=u+e,this.splice("_results",e-1,1,t)}}})</script> </dom-module><dom-module id="task-page" assetpath="/res/imp/taskpage/"> <template> <style include="iron-flex iron-flex-alignment swarming-app-style single-page-style task-style">.milo{width:calc(100% - 11px);height:2000px}.right{margin-top:8px}.break-all{word-break:break-all}.expand{min-width:3em;vertical-align:middle;padding:.5em}.code{font-family:monospace}.stdout{white-space:pre-line;padding:2px}.refresh_input{padding:0 5px}.reproduce{margin-left:5px}.tabbed{border:3px solid #1F78B4;margin-left:5px;min-height:80vh;min-width:550px}.task-info{min-width:500px}.cipd-header{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;margin-left:8px}</style> <url-param name="id" value="{{task_id}}"> </url-param> <url-param name="try_detail" value="{{_try_detail}}"> </url-param> <url-param name="request_detail" value="{{_request_detail}}"> </url-param> <url-param name="show_raw" value="{{_show_raw}}"> </url-param> <url-param name="refresh" value="{{_refresh_interval}}" default_value="10"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" profile="{{_profile}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,busy2)]]" name="Swarming Task Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-page-data id="data" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" busy="{{_busy1}}" request="{{_request}}" result="{{_result}}" stdout="{{_stdout}}" task_exists="{{_task_exists}}"> </task-page-data> <div class="horizontal layout wrap"> <div class="left flex"> <div class="horizontal layout"> <paper-input class="id_input" label="Task id" value="{{task_id}}"></paper-input> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> <button on-click="_promptRetry">Retry</button> <template is="dom-if" if="[[_canCancelTask(_result,_permissions)]]"> <button on-click="_promptCancel">Cancel</button> </template> </div> <h2 hidden$="[[_task_exists]]">Task not found.</h2> <template is="dom-if" if="[[_disambiguate(task_id,_result)]]"> <h2>Displaying a summary for a task with multiple tries</h2> <task-disambiguation busy="{{busy2}}" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" summary_result="[[_result]]"> </task-disambiguation> </template> <table class="task-info" hidden$="[[_not(_task_exists)]]"> <tbody> <tr> <td>Name</td> <td>[[_request.name]]</td> </tr> <tr> <td>State</td> <td class$="[[_stateClass(_result)]]">[[state(_result)]]</td> </tr> <tr> <td>Created</td> <td title$="[[_request.created_ts]]">[[_request.human_created_ts]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>Started</td> <td title$="[[_result.started_ts]]">[[_result.human_started_ts]]</td> </tr> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> <tr> <td>Expires</td> <td>[[_expires(_request)]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_completed_ts]]"> <tr> <td>Completed</td> <td title$="[[_result.completed_ts]]">[[_result.human_completed_ts]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_abandoned_ts]]"> <tr> <td>Abandoned</td> <td title$="[[_result.abandoned_ts]]">[[_result.human_abandoned_ts]]</td> </tr> </template> <tr> <td>Last Updated</td> <td title$="[[_result.modified_ts]]">[[_result.human_modified_ts]]</td> </tr> <template is="dom-if" if="[[_result.deduped_from]]"> <tr> <td><b>Deduped from</b></td> <td> <a href$="[[_taskLink(_result.deduped_from)]]"> [[_result.deduped_from]] </a> </td> </tr> </template> <tr> <td>Pending Time</td> <td>[[_pending(_result)]]</td> </tr> <tr> <td>Duration</td> <td>[[_result.human_duration]]</td> </tr> <tr> <td>Priority</td> <td>[[_request.priority]]</td> </tr> <tr> <td>User</td> <td>[[_request.user]]</td> </tr> <tr> <td>Authenticated</td> <td>[[_request.authenticated]]</td> </tr> <template is="dom-if" if="[[_request.service_account]]"> <tr> <td>Service Account</td> <td>[[_request.service_account]]</td> </tr> </template> <template is="dom-if" if="[[_request.properties.secret_bytes]]"> <tr> <td>Secret Bytes</td> <td>[[_request.properties.secret_bytes]]</td> </tr> </template> <template is="dom-if" if="[[_request.parent_task_id]]"> <tr> <td>Parent Task</td> <td> <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request.parent_task_id]]</a> </td> </tr> </template> <tr> <td rowspan$="[[_rowspan(_request.properties.dimensions)]]"> <a title="The list of bots that matches the list of dimensions" href$="[[_botListLink(_request.properties.dimensions)]]"> Requested Dimensions </a> </td> </tr> <template is="dom-repeat" items="{{_request.properties.dimensions}}" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Isolated Inputs</td> <td> <a href$="[[_isolateLink(_request.properties.inputs_ref)]]"> [[_request.properties.inputs_ref.isolated]] </a> </td> </tr> <template is="dom-if" if="[[_request.properties.outputs.length]]"> <tr> <td rowspan$="[[_rowspan(_request.properties.outputs)]]">Expected outputs</td> </tr> <template is="dom-repeat" items="{{_request.properties.outputs}}" as="output"> <tr> <td>[[output]]</td> </tr> </template> </template> <template is="dom-if" if="[[_not(_request_detail)]]"> <tr> <td>More Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Hide Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </td> </tr> </template> </tbody> <tbody id="more_details" hidden$="[[!_request_detail]]"> <tr> <td>Extra Args</td> <td class="code break-all">[[_extraArgs(_request)]]</td> </tr> <tr> <td>Command</td> <td class="code break-all">[[_command(_request)]]</td> </tr> <tr> <td>Idempotent</td> <td>[[_request.properties.idempotent]]</td> </tr> <tr> <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td> </tr> <template is="dom-repeat" items="{{_request.tags}}" as="tag"> <tr> <td class="break-all">[[tag]]</td> </tr> </template> <tr> <td>Execution timeout</td> <td>[[_humanDuration(_request.properties.execution_timeout_secs)]]</td> </tr> <tr> <td>I/O timeout</td> <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</td> </tr> <tr> <td>Grace period</td> <td>[[_humanDuration(_request.properties.grace_period_secs)]]</td> </tr> <tr> <td>CIPD server</td> <td> <a href$="[[_request.properties.cipd_input.server]]"> [[_request.properties.cipd_input.server]] </a> </td> </tr> <tr> <td>CIPD version</td> <td class="break-all">[[_request.properties.cipd_input.client_package.version]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>CIPD package name</td> <td>[[_result.cipd_pins.client_package.package_name]]</td> </tr> </template> <tr hidden$="[[_not(_request.properties.cipd_input)]]"> <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD packages</td> </tr> <template is="dom-repeat" items="[[_cipdPackages(_request,_result)]]" as="cipd"> <tr> <td>[[cipd.path]]/</td> </tr> <tr> <td class="break-all"> <span class="cipd-header">Requested: </span>[[cipd.requested]] </td> </tr> <tr hidden$="[[!_hasActualCIPDPackages(_result)]]"> <td class="break-all"> <span class="cipd-header">Actual: </span>[[cipd.actual]] </td> </tr> </template> <tr hidden$="[[_empty(_request.properties.caches)]]"> <td rowspan$="[[_rowspan(_request.properties.caches)]]">Named caches</td> </tr> <template is="dom-repeat" items="[[_request.properties.caches]]" as="cache"> <tr> <td><span>[[cache.name]]</span>:<span>[[cache.path]]</span></td> </tr> </template> </tbody> </table> <div class="title" hidden$="[[_not(_task_exists)]]">Task Execution</div> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Bot assigned to task</td> <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]]</a></td> </tr> <tr> <td rowspan$="[[_rowspan(_result.bot_dimensions)]]"> <a>Bot Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_result.bot_dimensions]]" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Exit code</td> <td>[[_result.exit_code]]</td> </tr> <tr> <td>Try number</td> <td>[[_result.try_number]]</td> </tr> <tr> <td>Failure</td> <td class$="[[_failureClass(_result.failure)]]">[[_result.failure]]</td> </tr> <tr> <td>Internal Failure</td> <td class$="[[_internalClass(_result.internal_failure)]]">[[_result.internal_failure]]</td> </tr> <tr> <td>Isolated Outputs</td> <td> <a href$="[[_isolateLink(_result.outputs_ref)]]"> [[_result.outputs_ref.isolated]] </a> </td> </tr> <tr> <td>Bot version</td> <td>[[_result.bot_version]]</td> </tr> <tr> <td>Server version</td> <td>[[_result.server_versions]]</td> </tr> </tbody></table> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> This space left blank until a bot is assigned to the task. </template> <template is="dom-if" if="[[_result.performance_stats]]"> <div class="title">Performance Stats</div> <table> <tbody><tr> <td title="This includes time taken to download inputs, isolate outputs, and setup CIPD">Total Overhead</td> <td>[[_humanDuration(_result.performance_stats.bot_overhead)]]</td> </tr> <tr> <td>Downloading Inputs From Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_download.duration)]]</td> </tr> <tr> <td>Uploading Outputs To Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_upload.duration)]]</td> </tr> <tr hidden$="[[!_result.performance_stats.isolated_download.initial_size]]"> <td>Initial bot cache</td> <td>[[_result.performance_stats.isolated_download.initial_number_items]] items; [[_bytes(_result.performance_stats.isolated_download.initial_size)]]</td> </tr> </tbody></table> </template> <div hidden$="[[_not(_task_exists)]]"> <div class="title">Reproducing the task locally</div> <div class="reproduce"> <div>Download inputs files into directory <i>foo</i>:</div> <div class="code"> python isolateserver.py download -I [[_request.properties.inputs_ref.isolatedserver]] --namespace [[_request.properties.inputs_ref.namespace]] -s [[_request.properties.inputs_ref.isolated]] --target foo</div> <br> <div>Run this task locally:</div> <div class="code"> python swarming.py reproduce -S [[_host_url]] [[task_id]]</div> <br> <div>Download output results into directory <i>foo</i>:</div> <div class="code"> python swarming.py collect -S [[_host_url]] --task-output-dir=foo [[task_id]]</div> <br> <div>Looking for <i>swarming.py</i>?</div> <div class="code"> git clone https://github.com/luci/client-py</div> </div> </div> </div> <div class="flex right" hidden$="[[_not(_task_exists)]]"> <div class="horizontal layout"> <div class="tabs"> <paper-tabs selected="{{_show_raw}}" no-bar=""> <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</paper-tab> <paper-tab>Raw Output</paper-tab> </paper-tabs> </div> <paper-input class="refresh_input" label="Refresh Interval (seconds)" value="{{_refresh_interval}}" title="How often to refresh all information about the task" auto-validate="" min="1" max="1000" pattern="[0-9]+"> </paper-input> </div> <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]"> <div class="milo tabbed" hidden$="[[_isSummaryLink(task_id)]]"> Milo results are only generated for task summaires, that is, tasks whose ids end in 0. Tasks ending in 1 or 2 represent possible retries of tasks. See <a href="//goo.gl/LE4rwV">the docs</a> for more. </div> <iframe id="miloFrame" class="milo tabbed" src$="[[_getDisplayServerLink(_server_details.display_server_url_template,task_id)]]"></iframe> </template> <template is="dom-if" if="[[_show_raw]]"> <div class="code stdout tabbed break-all">[[_rawOutput(_stdout,_result)]]</div> </template> </div> </div> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialog_prompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <interval-timer period="[[_refresh_interval]]" on-trigger="_softRefresh"> </interval-timer> </template> <script>!function(){Polymer({is:"task-page",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{task_id:{type:String},client_id:{type:String},_dialog_prompt:{type:String,value:""},_host_url:{type:String,value:function(){return window.location.hostname}},_refresh_interval:{type:Number},_request:{type:Object,observer:"_requestUpdated"},_request_detail:{type:Boolean},_result:{type:Object},_server_details:{type:Object},_stdout:{type:String}},_alias:function(t){var e=t.value;return Array.isArray(e)||(e=[e]),swarming.alias.has(t.key)&&e.forEach(function(i,s){e[s]=swarming.alias.apply(i,t.key)}),e.join(" | ")},_bytes:function(t){return sk.human.bytes(t)},_canCancelTask:function(t,e){return t&&"PENDING"===t.state&&e.cancel_task},_cancelTask:function(){var t="/api/swarming/v1/task/"+this.task_id+"/cancel";swarming.postWithToast(t,"Canceling task "+this.task_id,this._auth_headers)},_cipdRowspan:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return 0;var i=(t.properties.cipd_input.packages||[]).length;return i*=this._hasActualCIPDPackages(e)?3:2,i+1},_cipdPackages:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return[];var i=t.properties.cipd_input.packages||[],s=e&&e.cipd_pins&&e.cipd_pins.packages||[];return i.forEach(function(t){t.requested=t.package_name+":"+t.version,s.forEach(function(e){e.path===t.path&&(t.actual=e.package_name+":"+e.version)})}),i},_command:function(t){if(!t||!t.properties)return"";var e=t.properties.command||[];return e.join(" ")},_disambiguate:function(t,e){return!(!t.endsWith("0")||!e)&&e.try_number>1},_empty:function(t){return!t||0==t.length},_expires:function(t){var e=parseInt(t.expiration_secs);return e?sk.human.localeTime(new Date(t.created_ts.getTime()+1e3*e)):t.expiration_secs+" seconds from created time"},_extraArgs:function(t){if(!t||!t.properties)return"";var e=t.properties.extra_args||[];return e.join(" ")},_failureClass:function(t){return t?"failed_task":""},_getDisplayServerLink:function(t,e){if(t)return t.replace("%s",e)},_hasActualCIPDPackages:function(t){return t&&t.cipd_pins&&t.cipd_pins.packages},_internalClass:function(t){return t?"exception":""},_isolateLink:function(t){if(t&&t.isolatedserver)return t.isolatedserver+"/browse?namespace="+t.namespace+"&hash="+t.isolated},_isSummaryLink:function(t){return t&&t.endsWith(0)},_noMilo:function(t){return!this._tag(t,"allow_milo")},_pending:function(t){if(!t.created_ts)return"";var e=t.started_ts||t.abandoned_ts||new Date;return e<=t.created_ts?"0s":this._timeDiffExact(t.created_ts,e)},_promptClosed:function(t){t.detail.confirmed&&(this._dialog_prompt.startsWith("cancel")?this._cancelTask():this._retryTask())},_promptCancel:function(){this.set("_dialog_prompt","cancel task "+this.task_id),this.$.prompt.open()},_promptRetry:function(){this.set("_dialog_prompt","retry task "+this.task_id),this.$.prompt.open()},_rawOutput:function(t,e){return t?t:"PENDING"===e.state||"RUNNING"===e.state?"[No output yet]":"[No output received]"},_refresh:function(){this.$.data.reload()},_requestUpdated:function(t){this._noMilo(t)&&this.set("_show_raw",1)},_softRefresh:function(){if(!this._result||"RUNNING"===this._result.state||"PENDING"===this._result.state){this.$.data.reload();var t=this.$$("iframe");t&&(t.src=this._getDisplayServerLink(this._server_details.display_server_url_template,this.task_id))}},_retryTask:function(){if(!this._request)return void sk.errorMessage("Task not yet loaded",3e3);var t={expiration_secs:this._request.expiration_secs,name:this._request.name+" (retry)",parent_task_id:this._request.parent_task_id,priority:this._request.priority,properties:this._request.properties,tags:this._request.tags,user:this._profile.email,service_account:this._request.service_account};t.properties.idempotent=!1,swarming.postWithToast("/api/swarming/v1/tasks/new","Retrying task "+this.task_id,this._auth_headers,t).then(function(t){if(t=JSON.parse(t),t&&t.task_id){var e={id:this.task_id};history.pushState(e,"Task Page"),this.set("task_id",t.task_id)}}.bind(this),function(t){console.log("Task could not be retried",t)})},_rowspan:function(t){return t=t||[],t.length+1},_supportsMilo:function(t,e){return!e&&t&&this._tag(t,"allow_milo")},_toggleDetails:function(){this.set("_request_detail",!this._request_detail)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_wasPickedUp:function(t){return t&&t.state!==this.PENDING&&t.state!==this.CANCELED&&t.state!=this.EXPIRED},_wasNotPickedUp:function(t){return t&&!this._wasPickedUp(t)}})}()</script> </dom-module> </div></body></html>
|
| + })(); </script> </dom-module><dom-module id="interval-timer" assetpath="/res/imp/common/"> <script>!function(){Polymer({is:"interval-timer",properties:{period:{type:Number,value:-1,observer:"_periodChanged"}},_periodChanged:function(e){this._timeout&&window.clearTimeout(this._timeout),e>0&&(this._timeout=window.setTimeout(function(){this.fire("trigger"),this._periodChanged(e)}.bind(this),1e3*e))}})}()</script> </dom-module> <dom-module id="task-page-data" assetpath="/res/imp/taskpage/"> <script>!function(){var t,e=400,s=["abandoned_ts","completed_ts","created_ts","modified_ts","started_ts"];Polymer({is:"task-page-data",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},task_id:{type:String},busy:{type:Boolean,computed:"_or(_busy1,_busy2,_busy3)",notify:!0},request:{type:Object,computed:"_parseRequest(_request)",notify:!0},result:{type:Object,computed:"_parseResult(_result)",notify:!0},stdout:{type:String,computed:"_parseStdout(_stdout)",notify:!0},task_exists:{type:Boolean,value:!0,notify:!0},_busy1:{type:Boolean,value:!1},_busy2:{type:Boolean,value:!1},_busy3:{type:Boolean,value:!1},_request:{type:Object},_result:{type:Object},_stdout:{type:Object}},observers:["reload(auth_headers,task_id)"],reload:function(){if(!this.task_id||!this.auth_headers)return void console.log("task_id and auth_headers can't be empty");t&&this.cancelAsync(t);var s="/api/swarming/v1/task/"+this.task_id;t=this.async(function(){t=void 0;var e=this._getJsonAsync("_request",s+"/request","_busy1",this.auth_headers);e.then(function(){this.set("task_exists",!0)}.bind(this)).catch(function(t){404===t.status?this.set("task_exists",!1):sk.errorMessage("Http response: "+(t.status||" ")+" "+t.response)}.bind(this)),this._getJsonAsync("_result",s+"/result?include_performance_stats=true","_busy2",this.auth_headers),this.reloadStdout()},e)},_parseRequest:function(t){return t?(t.tagMap={},t.tags=t.tags||[],t.tags.forEach(function(e){var s=e.split(":",1),a=s[0],u=e.substring(a.length+1);t.tagMap[a]=u}),s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),t):{}},_parseResult:function(t){if(!t)return{};var e=new Date;return s.forEach(function(e){t[e]&&(t[e]=new Date(t[e]),t["human_"+e]=sk.human.localeTime(t[e]))}),!t.duration&&t.state===this.RUNNING&&t.started_ts&&(t.duration=(e-t.started_ts)/1e3),t.duration&&(t.human_duration=this._humanDuration(t.duration)),t},_parseStdout:function(t){return t&&t.output?t.output:""},reloadStdout:function(){this._getJsonAsync("_stdout","/api/swarming/v1/task/"+this.task_id+"/stdout","_busy3",this.auth_headers)}})}()</script> </dom-module><dom-module id="task-disambiguation" assetpath="/res/imp/taskpage/"> <template> <style include="swarming-app-style single-page-style task-style"></style> <table> <thead> <tr> <th>Try ID</th> <th>Bot ID</th> <th>Status</th> </tr> </thead> <tbody> <template id="result_list" is="dom-repeat" items="[[_results]]" as="result" observe="task_id bot_id state"> <tr> <td> <a href$="[[_taskLink(result.task_id,'true')]]"> [[result.task_id]] </a> </td> <td> <a href$="[[_botLink(result.bot_id)]]"> [[result.bot_id]] </a> </td> <td class$="[[_stateClass(result)]]">[[state(result)]]</td> </tr> </template> </tbody> </table> </template> <script>Polymer({is:"task-disambiguation",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{auth_headers:{type:Object},summary_result:{type:Object},task_id:{type:String},busy:{type:Boolean,value:!1,notify:!0},_busyArr:{type:Array,value:function(){return[]}},_results:{type:Array,value:function(){return[]}}},observers:["_fetchRest(auth_headers,task_id,summary_result)","_computeBusy(_busyArr.*)"],_computeBusy:function(){for(var s=0;s<this._busyArr.length;s++)if(this._busyArr[s].status)return!0;return!1},_fetchRest:function(s,r,t){if(s&&r&&t){var e=t.try_number;this.set("_busyArr",[]),this.set("_results",[]);for(var u=r.substring(0,r.length-1),i="/api/swarming/v1/task/",a=0;a<e-1;a++){var n=u+(a+1);this.splice("_busyArr",a,0,{}),this.splice("_results",a,0,{task_id:n}),this._getJsonAsyncArr(a,"_results",i+n+"/result","_busyArr",s)}t.task_id=u+e,this.splice("_results",e-1,1,t)}}})</script> </dom-module><dom-module id="task-page" assetpath="/res/imp/taskpage/"> <template> <style include="iron-flex iron-flex-alignment swarming-app-style single-page-style task-style">.milo{width:calc(100% - 11px);height:2000px}.right{margin-top:8px}.break-all{word-break:break-all}.expand{min-width:3em;vertical-align:middle;padding:.5em}.code{font-family:monospace}.stdout{white-space:pre-wrap;padding:2px}.stdout.wide{white-space:pre;overflow-x:auto}.refresh_input{padding:0 5px}.reproduce{margin-left:5px}.tabbed{border:3px solid #1F78B4;margin-left:5px;min-height:80vh;min-width:550px}.task-info{min-width:500px}.cipd-header{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;margin-left:8px}.full-width{min-width:100%}.full-width-container{position:relative}.full-width-container>paper-checkbox{position:absolute;bottom:10px;width:140px;left:5px}</style> <url-param name="id" value="{{task_id}}"> </url-param> <url-param name="try_detail" value="{{_try_detail}}"> </url-param> <url-param name="request_detail" value="{{_request_detail}}"> </url-param> <url-param name="show_raw" value="{{_show_raw}}"> </url-param> <url-param name="wide_logs" value="{{_wide_logs}}"> </url-param> <url-param name="refresh" value="{{_refresh_interval}}" default_value="10"> </url-param> <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" permissions="{{_permissions}}" profile="{{_profile}}" server_details="{{_server_details}}" signed_in="{{_signed_in}}" busy="[[_or(_busy1,busy2)]]" name="Swarming Task Page"> <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> <div hidden$="[[_not(_signed_in)]]"> <task-page-data id="data" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" busy="{{_busy1}}" request="{{_request}}" result="{{_result}}" stdout="{{_stdout}}" task_exists="{{_task_exists}}"> </task-page-data> <div class="horizontal layout wrap"> <div class="left flex"> <div class="horizontal layout"> <paper-input class="id_input" label="Task id" value="{{task_id}}"></paper-input> <button on-click="_refresh"> <iron-icon class="refresh" icon="icons:refresh"></iron-icon> </button> <button on-click="_promptRetry">Retry</button> <template is="dom-if" if="[[_canCancelTask(_result,_permissions)]]"> <button on-click="_promptCancel">Cancel</button> </template> </div> <h2 hidden$="[[_task_exists]]">Task not found.</h2> <template is="dom-if" if="[[_disambiguate(task_id,_result)]]"> <h2>Displaying a summary for a task with multiple tries</h2> <task-disambiguation busy="{{busy2}}" auth_headers="[[_auth_headers]]" task_id="[[task_id]]" summary_result="[[_result]]"> </task-disambiguation> </template> <table class="task-info" hidden$="[[_not(_task_exists)]]"> <tbody> <tr> <td>Name</td> <td>[[_request.name]]</td> </tr> <tr> <td>State</td> <td class$="[[_stateClass(_result)]]">[[state(_result)]]</td> </tr> <tr> <td>Created</td> <td title$="[[_request.created_ts]]">[[_request.human_created_ts]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>Started</td> <td title$="[[_result.started_ts]]">[[_result.human_started_ts]]</td> </tr> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> <tr> <td>Expires</td> <td>[[_expires(_request)]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_completed_ts]]"> <tr> <td>Completed</td> <td title$="[[_result.completed_ts]]">[[_result.human_completed_ts]]</td> </tr> </template> <template is="dom-if" if="[[_result.human_abandoned_ts]]"> <tr> <td>Abandoned</td> <td title$="[[_result.abandoned_ts]]">[[_result.human_abandoned_ts]]</td> </tr> </template> <tr> <td>Last Updated</td> <td title$="[[_result.modified_ts]]">[[_result.human_modified_ts]]</td> </tr> <template is="dom-if" if="[[_result.deduped_from]]"> <tr> <td><b>Deduped from</b></td> <td> <a href$="[[_taskLink(_result.deduped_from)]]"> [[_result.deduped_from]] </a> </td> </tr> </template> <tr> <td>Pending Time</td> <td>[[_pending(_result)]]</td> </tr> <tr> <td>Duration</td> <td>[[_result.human_duration]]</td> </tr> <tr> <td>Priority</td> <td>[[_request.priority]]</td> </tr> <tr> <td>User</td> <td>[[_request.user]]</td> </tr> <tr> <td>Authenticated</td> <td>[[_request.authenticated]]</td> </tr> <template is="dom-if" if="[[_request.service_account]]"> <tr> <td>Service Account</td> <td>[[_request.service_account]]</td> </tr> </template> <template is="dom-if" if="[[_request.properties.secret_bytes]]"> <tr> <td>Secret Bytes</td> <td>[[_request.properties.secret_bytes]]</td> </tr> </template> <template is="dom-if" if="[[_request.parent_task_id]]"> <tr> <td>Parent Task</td> <td> <a href$="[[_taskLink(_request.parent_task_id)]]">[[_request.parent_task_id]]</a> </td> </tr> </template> <tr> <td rowspan$="[[_rowspan(_request.properties.dimensions)]]"> <a title="The list of bots that matches the list of dimensions" href$="[[_botListLink(_request.properties.dimensions)]]"> Requested Dimensions </a> </td> </tr> <template is="dom-repeat" items="{{_request.properties.dimensions}}" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Isolated Inputs</td> <td> <a href$="[[_isolateLink(_request.properties.inputs_ref)]]"> [[_request.properties.inputs_ref.isolated]] </a> </td> </tr> <template is="dom-if" if="[[_request.properties.outputs.length]]"> <tr> <td rowspan$="[[_rowspan(_request.properties.outputs)]]">Expected outputs</td> </tr> <template is="dom-repeat" items="{{_request.properties.outputs}}" as="output"> <tr> <td>[[output]]</td> </tr> </template> </template> <template is="dom-if" if="[[_not(_request_detail)]]"> <tr> <td>More Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:add-circle-outline"></iron-icon> </button> </td> </tr> </template> <template is="dom-if" if="[[_request_detail]]"> <tr> <td>Hide Details</td> <td> <button on-click="_toggleDetails"> <iron-icon icon="icons:remove-circle-outline"></iron-icon> </button> </td> </tr> </template> </tbody> <tbody id="more_details" hidden$="[[!_request_detail]]"> <tr> <td>Extra Args</td> <td class="code break-all">[[_extraArgs(_request)]]</td> </tr> <tr> <td>Command</td> <td class="code break-all">[[_command(_request)]]</td> </tr> <tr> <td>Idempotent</td> <td>[[_request.properties.idempotent]]</td> </tr> <tr> <td rowspan$="[[_rowspan(_request.tags)]]">Tags</td> </tr> <template is="dom-repeat" items="{{_request.tags}}" as="tag"> <tr> <td class="break-all">[[tag]]</td> </tr> </template> <tr> <td>Execution timeout</td> <td>[[_humanDuration(_request.properties.execution_timeout_secs)]]</td> </tr> <tr> <td>I/O timeout</td> <td>[[_humanDuration(_request.properties.io_timeout_secs)]]</td> </tr> <tr> <td>Grace period</td> <td>[[_humanDuration(_request.properties.grace_period_secs)]]</td> </tr> <tr> <td>CIPD server</td> <td> <a href$="[[_request.properties.cipd_input.server]]"> [[_request.properties.cipd_input.server]] </a> </td> </tr> <tr> <td>CIPD version</td> <td class="break-all">[[_request.properties.cipd_input.client_package.version]]</td> </tr> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <tr> <td>CIPD package name</td> <td>[[_result.cipd_pins.client_package.package_name]]</td> </tr> </template> <tr hidden$="[[_not(_request.properties.cipd_input)]]"> <td rowspan$="[[_cipdRowspan(_request,_result)]]">CIPD packages</td> </tr> <template is="dom-repeat" items="[[_cipdPackages(_request,_result)]]" as="cipd"> <tr> <td>[[cipd.path]]/</td> </tr> <tr> <td class="break-all"> <span class="cipd-header">Requested: </span>[[cipd.requested]] </td> </tr> <tr hidden$="[[!_hasActualCIPDPackages(_result)]]"> <td class="break-all"> <span class="cipd-header">Actual: </span>[[cipd.actual]] </td> </tr> </template> <tr hidden$="[[_empty(_request.properties.caches)]]"> <td rowspan$="[[_rowspan(_request.properties.caches)]]">Named caches</td> </tr> <template is="dom-repeat" items="[[_request.properties.caches]]" as="cache"> <tr> <td><span>[[cache.name]]</span>:<span>[[cache.path]]</span></td> </tr> </template> </tbody> </table> <div class="title" hidden$="[[_not(_task_exists)]]">Task Execution</div> <template is="dom-if" if="[[_wasPickedUp(_result)]]"> <table hidden$="[[_not(_task_exists)]]"> <tbody><tr> <td>Bot assigned to task</td> <td><a href$="[[_botLink(_result.bot_id)]]">[[_result.bot_id]]</a></td> </tr> <tr> <td rowspan$="[[_rowspan(_result.bot_dimensions)]]"> <a>Bot Dimensions</a> </td> </tr> <template is="dom-repeat" items="[[_result.bot_dimensions]]" as="dimension"> <tr> <td><b>[[dimension.key]]:</b> [[_alias(dimension)]]</td> </tr> </template> <tr> <td>Exit code</td> <td>[[_result.exit_code]]</td> </tr> <tr> <td>Try number</td> <td>[[_result.try_number]]</td> </tr> <tr> <td>Failure</td> <td class$="[[_failureClass(_result.failure)]]">[[_result.failure]]</td> </tr> <tr> <td>Internal Failure</td> <td class$="[[_internalClass(_result.internal_failure)]]">[[_result.internal_failure]]</td> </tr> <tr> <td>Isolated Outputs</td> <td> <a href$="[[_isolateLink(_result.outputs_ref)]]"> [[_result.outputs_ref.isolated]] </a> </td> </tr> <tr> <td>Bot version</td> <td>[[_result.bot_version]]</td> </tr> <tr> <td>Server version</td> <td>[[_result.server_versions]]</td> </tr> </tbody></table> </template> <template is="dom-if" if="[[_wasNotPickedUp(_result)]]"> This space left blank until a bot is assigned to the task. </template> <template is="dom-if" if="[[_result.performance_stats]]"> <div class="title">Performance Stats</div> <table> <tbody><tr> <td title="This includes time taken to download inputs, isolate outputs, and setup CIPD">Total Overhead</td> <td>[[_humanDuration(_result.performance_stats.bot_overhead)]]</td> </tr> <tr> <td>Downloading Inputs From Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_download.duration)]]</td> </tr> <tr> <td>Uploading Outputs To Isolate</td> <td>[[_humanDuration(_result.performance_stats.isolated_upload.duration)]]</td> </tr> <tr hidden$="[[!_result.performance_stats.isolated_download.initial_size]]"> <td>Initial bot cache</td> <td>[[_result.performance_stats.isolated_download.initial_number_items]] items; [[_bytes(_result.performance_stats.isolated_download.initial_size)]]</td> </tr> </tbody></table> </template> <div hidden$="[[_not(_task_exists)]]"> <div class="title">Reproducing the task locally</div> <div class="reproduce"> <div>Download inputs files into directory <i>foo</i>:</div> <div class="code"> python isolateserver.py download -I [[_request.properties.inputs_ref.isolatedserver]] --namespace [[_request.properties.inputs_ref.namespace]] -s [[_request.properties.inputs_ref.isolated]] --target foo</div> <br> <div>Run this task locally:</div> <div class="code"> python swarming.py reproduce -S [[_host_url]] [[task_id]]</div> <br> <div>Download output results into directory <i>foo</i>:</div> <div class="code"> python swarming.py collect -S [[_host_url]] --task-output-dir=foo [[task_id]]</div> <br> <div>Looking for <i>swarming.py</i>?</div> <div class="code"> git clone https://github.com/luci/client-py</div> </div> </div> </div> <div class$="flex right [[_classRight(_wide_logs)]]" hidden$="[[_not(_task_exists)]]"> <div class="horizontal layout"> <div class="tabs"> <paper-tabs selected="{{_show_raw}}" no-bar=""> <paper-tab disabled$="[[_noMilo(_request)]]">Milo Output</paper-tab> <paper-tab>Raw Output</paper-tab> </paper-tabs> </div> <paper-input class="refresh_input" label="Refresh Interval (seconds)" value="{{_refresh_interval}}" title="How often to refresh all information about the task" auto-validate="" min="1" max="1000" pattern="[0-9]+"> </paper-input> <div class="full-width-container"> <paper-checkbox checked="{{_wide_logs}}"> Full Width Logs </paper-checkbox> </div> </div> <template is="dom-if" if="[[_supportsMilo(_request,_show_raw)]]"> <div class="milo tabbed" hidden$="[[_isSummaryLink(task_id)]]"> Milo results are only generated for task summaires, that is, tasks whose ids end in 0. Tasks ending in 1 or 2 represent possible retries of tasks. See <a href="//goo.gl/LE4rwV">the docs</a> for more. </div> <iframe id="miloFrame" class="milo tabbed" src$="[[_getDisplayServerLink(_server_details.display_server_url_template,task_id)]]"></iframe> </template> <template is="dom-if" if="[[_show_raw]]"> <div class$="code stdout tabbed break-all [[_classStdout(_wide_logs)]]">[[_rawOutput(_stdout,_result)]]</div> </template> </div> </div> </div> </swarming-app> <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed"> <h2>Are you sure?</h2> <div>Are you sure you want to [[_dialog_prompt]]?</div> <div class="buttons"> <paper-button dialog-dismiss="" autofocus="">No</paper-button> <paper-button dialog-confirm="">Yes</paper-button> </div> </paper-dialog> <interval-timer period="[[_refresh_interval]]" on-trigger="_softRefresh"> </interval-timer> </template> <script>!function(){Polymer({is:"task-page",behaviors:[SwarmingBehaviors.CommonBehavior,SwarmingBehaviors.TaskBehavior],properties:{task_id:{type:String},client_id:{type:String},_dialog_prompt:{type:String,value:""},_host_url:{type:String,value:function(){return window.location.hostname}},_refresh_interval:{type:Number},_request:{type:Object,observer:"_requestUpdated"},_request_detail:{type:Boolean},_result:{type:Object},_server_details:{type:Object},_stdout:{type:String}},_alias:function(t){var e=t.value;return Array.isArray(e)||(e=[e]),swarming.alias.has(t.key)&&e.forEach(function(i,s){e[s]=swarming.alias.apply(i,t.key)}),e.join(" | ")},_bytes:function(t){return sk.human.bytes(t)},_canCancelTask:function(t,e){return t&&"PENDING"===t.state&&e.cancel_task},_cancelTask:function(){var t="/api/swarming/v1/task/"+this.task_id+"/cancel";swarming.postWithToast(t,"Canceling task "+this.task_id,this._auth_headers)},_cipdRowspan:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return 0;var i=(t.properties.cipd_input.packages||[]).length;return i*=this._hasActualCIPDPackages(e)?3:2,i+1},_cipdPackages:function(t,e){if(!t||!t.properties||!t.properties.cipd_input)return[];var i=t.properties.cipd_input.packages||[],s=e&&e.cipd_pins&&e.cipd_pins.packages||[];return i.forEach(function(t){t.requested=t.package_name+":"+t.version,s.forEach(function(e){e.path===t.path&&(t.actual=e.package_name+":"+e.version)})}),i},_classRight:function(t){return t?"full-width":""},_classStdout:function(t){return t?"wide":""},_command:function(t){if(!t||!t.properties)return"";var e=t.properties.command||[];return e.join(" ")},_disambiguate:function(t,e){return!(!t.endsWith("0")||!e)&&e.try_number>1},_empty:function(t){return!t||0==t.length},_expires:function(t){var e=parseInt(t.expiration_secs);return e?sk.human.localeTime(new Date(t.created_ts.getTime()+1e3*e)):t.expiration_secs+" seconds from created time"},_extraArgs:function(t){if(!t||!t.properties)return"";var e=t.properties.extra_args||[];return e.join(" ")},_failureClass:function(t){return t?"failed_task":""},_getDisplayServerLink:function(t,e){if(t)return t.replace("%s",e)},_hasActualCIPDPackages:function(t){return t&&t.cipd_pins&&t.cipd_pins.packages},_internalClass:function(t){return t?"exception":""},_isolateLink:function(t){if(t&&t.isolatedserver)return t.isolatedserver+"/browse?namespace="+t.namespace+"&hash="+t.isolated},_isSummaryLink:function(t){return t&&t.endsWith(0)},_noMilo:function(t){return!this._tag(t,"allow_milo")},_pending:function(t){if(!t.created_ts)return"";var e=t.started_ts||t.abandoned_ts||new Date;return e<=t.created_ts?"0s":this._timeDiffExact(t.created_ts,e)},_promptClosed:function(t){t.detail.confirmed&&(this._dialog_prompt.startsWith("cancel")?this._cancelTask():this._retryTask())},_promptCancel:function(){this.set("_dialog_prompt","cancel task "+this.task_id),this.$.prompt.open()},_promptRetry:function(){this.set("_dialog_prompt","retry task "+this.task_id),this.$.prompt.open()},_rawOutput:function(t,e){return t?t:"PENDING"===e.state||"RUNNING"===e.state?"[No output yet]":"[No output received]"},_refresh:function(){this.$.data.reload()},_requestUpdated:function(t){this._noMilo(t)&&this.set("_show_raw",1)},_softRefresh:function(){if(!this._result||"RUNNING"===this._result.state||"PENDING"===this._result.state){this.$.data.reload();var t=this.$$("iframe");t&&(t.src=this._getDisplayServerLink(this._server_details.display_server_url_template,this.task_id))}},_retryTask:function(){if(!this._request)return void sk.errorMessage("Task not yet loaded",3e3);var t={expiration_secs:this._request.expiration_secs,name:this._request.name+" (retry)",parent_task_id:this._request.parent_task_id,priority:this._request.priority,properties:this._request.properties,tags:this._request.tags,user:this._profile.email,service_account:this._request.service_account};t.properties.idempotent=!1,swarming.postWithToast("/api/swarming/v1/tasks/new","Retrying task "+this.task_id,this._auth_headers,t).then(function(t){if(t=JSON.parse(t),t&&t.task_id){var e={id:this.task_id};history.pushState(e,"Task Page"),this.set("task_id",t.task_id)}}.bind(this),function(t){console.log("Task could not be retried",t)})},_rowspan:function(t){return t=t||[],t.length+1},_supportsMilo:function(t,e){return!e&&t&&this._tag(t,"allow_milo")},_toggleDetails:function(){this.set("_request_detail",!this._request_detail)},_tag:function(t,e){if(t&&t.tagMap)return t.tagMap[e]},_wasPickedUp:function(t){return t&&t.state!==this.PENDING&&t.state!==this.CANCELED&&t.state!=this.EXPIRED},_wasNotPickedUp:function(t){return t&&!this._wasPickedUp(t)}})}()</script> </dom-module> </div></body></html>
|
|
|