Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(304)

Side by Side Diff: appengine/swarming/elements/build/elements.html

Issue 2302973002: Refactor post requests, implement bot cancel/terminate (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@basic-layout
Patch Set: Build using new skia-common-js Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 <!DOCTYPE html><html><head><!-- 1 <!DOCTYPE html><html><head><!--
2 @license 2 @license
3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved. 3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt 4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also 7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 --><!-- 9 --><!--
10 @license 10 @license
(...skipping 8128 matching lines...) Expand 10 before | Expand all | Expand 10 after
8139 }, 8139 },
8140 8140
8141 _or: function() { 8141 _or: function() {
8142 var result = false; 8142 var result = false;
8143 // can't use .foreach, as arguments isn't really an Array. 8143 // can't use .foreach, as arguments isn't really an Array.
8144 for (var i = 0; i < arguments.length; i++) { 8144 for (var i = 0; i < arguments.length; i++) {
8145 result = result || arguments[i]; 8145 result = result || arguments[i];
8146 } 8146 }
8147 return result; 8147 return result;
8148 }, 8148 },
8149
8150 // _postWithToast makes a post request and updates the provided paper-toas t
8151 // element with the response, regardless of failure.
8152 _postWithToast: function(url, msg, auth_headers) {
8153 // Keep toast displayed until we hear back from the request.
8154 sk.errorMessage(msg, 0);
8155
8156 sk.request("POST", url, undefined, auth_headers).then(function(response) {
8157 sk.errorMessage("Request sent. Response: "+response, 3000);
8158 }.bind(this)).catch(function(reason) {
8159 console.log("Request failed", reason);
8160 sk.errorMessage("Request failed. Reason: "+reason, 5000);
8161 }.bind(this));
8162 }
8149 }; 8163 };
8150 })(); 8164 })();
8151 </script> 8165 </script>
8152 <script> 8166 <script>
8153 Polymer.AppLayout = Polymer.AppLayout || {}; 8167 Polymer.AppLayout = Polymer.AppLayout || {};
8154 8168
8155 Polymer.AppLayout._scrollEffects = Polymer.AppLayout._scrollEffects || {}; 8169 Polymer.AppLayout._scrollEffects = Polymer.AppLayout._scrollEffects || {};
8156 8170
8157 Polymer.AppLayout.scrollTimingFunction = function easeOutQuad(t, b, c, d) { 8171 Polymer.AppLayout.scrollTimingFunction = function easeOutQuad(t, b, c, d) {
8158 t /= d; 8172 t /= d;
(...skipping 15800 matching lines...) Expand 10 before | Expand all | Expand 10 after
23959 Fired when the animation finishes. 23973 Fired when the animation finishes.
23960 This is useful if you want to wait until 23974 This is useful if you want to wait until
23961 the ripple animation finishes to perform some action. 23975 the ripple animation finishes to perform some action.
23962 23976
23963 @event transitionend 23977 @event transitionend
23964 Event param: {{node: Object}} detail Contains the animated node. 23978 Event param: {{node: Object}} detail Contains the animated node.
23965 */ 23979 */
23966 }); 23980 });
23967 </script> 23981 </script>
23968 </dom-module> 23982 </dom-module>
23983 <dom-module id="error-toast" assetpath="/res/imp/common/">
23984 <template>
23985 <paper-toast id="toast"></paper-toast>
23986 </template>
23987 </dom-module>
23988
23989 <script>
23990 Polymer({
23991 is: "error-toast",
23992 ready: function() {
23993 document.addEventListener('error-sk', function(e) {
23994 this.$.toast.close();
23995 if (e.detail.message) {
23996 this.$.toast.text = e.detail.message;
23997 var duration = 10000;
23998 // duration = 0 is a valid input for "keep open indefinitely".
23999 if (e.detail.duration !== undefined) {
24000 duration = e.detail.duration;
24001 }
24002 this.$.toast.duration = duration;
24003 this.$.toast.show();
24004 } else {
24005 console.log("Empty message?", e);
24006 }
24007 }.bind(this));
24008 },
24009 });
24010 </script>
23969 <dom-module id="task-filters" assetpath="/res/imp/tasklist/"> 24011 <dom-module id="task-filters" assetpath="/res/imp/tasklist/">
23970 <template> 24012 <template>
23971 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio ning query-column-filter-style"> 24013 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio ning query-column-filter-style">
23972 .item.wide { 24014 .item.wide {
23973 max-width: 400px; 24015 max-width: 400px;
23974 } 24016 }
23975 .selector.wide { 24017 .selector.wide {
23976 min-width: 275px; 24018 min-width: 275px;
23977 } 24019 }
23978 24020
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
24395 </url-param> 24437 </url-param>
24396 24438
24397 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Task List"> 24439 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Task List">
24398 24440
24399 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 24441 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
24400 24442
24401 <div hidden$="[[_not(_signed_in)]]"> 24443 <div hidden$="[[_not(_signed_in)]]">
24402 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_ params]]" tasks="{{_items}}" busy="{{_busy}}" primary_map="{{_primary_map}}" pri mary_arr="{{_primary_arr}}"> 24444 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_ params]]" tasks="{{_items}}" busy="{{_busy}}" primary_map="{{_primary_map}}" pri mary_arr="{{_primary_arr}}">
24403 </task-list-data> 24445 </task-list-data>
24404 24446
24405 <paper-toast id="toast"></paper-toast> 24447 <error-toast></error-toast>
24406 24448
24407 <div class="horizontal layout"> 24449 <div class="horizontal layout">
24408 24450
24409 <task-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_a rr]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter} }"> 24451 <task-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_a rr]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter} }">
24410 </task-filters> 24452 </task-filters>
24411 24453
24412 </div> 24454 </div>
24413 24455
24414 <table class="task-list"> 24456 <table class="task-list">
24415 <thead on-sort_change="_sortChange"> 24457 <thead on-sort_change="_sortChange">
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
24595 }, 24637 },
24596 24638
24597 _cancelTask: function(e) { 24639 _cancelTask: function(e) {
24598 var task = e.model.task; 24640 var task = e.model.task;
24599 if (!task || !task.task_id) { 24641 if (!task || !task.task_id) {
24600 console.log("Missing task info", task); 24642 console.log("Missing task info", task);
24601 return 24643 return
24602 } 24644 }
24603 var id = task.task_id 24645 var id = task.task_id
24604 24646
24605 // Keep toast displayed until we hear back from the cancel.
24606 this.$.toast.duration = 0;
24607 this.$.toast.text="Canceling task " + id;
24608 this.$.toast.open();
24609 var url = "/_ah/api/swarming/v1/task/" + id +"/cancel"; 24647 var url = "/_ah/api/swarming/v1/task/" + id +"/cancel";
24610 sk.request("POST", url, undefined, this._auth_headers).then(function(res ponse) { 24648 this._postWithToast(url, "Canceling task " + id, this._auth_headers);
24611 this.$.toast.close();
24612 this.$.toast.show({
24613 text: "Request sent. Response: "+response,
24614 duration: 3000,
24615 });
24616 }.bind(this)).catch(function(reason) {
24617 console.log("Cancellation failed", reason);
24618 this.$.toast.close();
24619 this.$.toast.show({
24620 text: "Request failed. Reason: "+reason,
24621 duration: 3000,
24622 });
24623 }.bind(this));
24624 }, 24649 },
24625 24650
24626 _tag: function(task, col) { 24651 _tag: function(task, col) {
24627 if (!task || !task.tagMap) { 24652 if (!task || !task.tagMap) {
24628 return undefined; 24653 return undefined;
24629 } 24654 }
24630 return task.tagMap[col]; 24655 return task.tagMap[col];
24631 }, 24656 },
24632 24657
24633 _taskLink: function(taskId) { 24658 _taskLink: function(taskId) {
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
24889 _calcSize: function() { 24914 _calcSize: function() {
24890 return this.getBoundingClientRect()[this.dimension] + 'px'; 24915 return this.getBoundingClientRect()[this.dimension] + 'px';
24891 } 24916 }
24892 24917
24893 }); 24918 });
24894 24919
24895 </script> 24920 </script>
24896 <script> 24921 <script>
24897 24922
24898 /** 24923 /**
24924 * `Polymer.NeonAnimatableBehavior` is implemented by elements containing anim ations for use with
24925 * elements implementing `Polymer.NeonAnimationRunnerBehavior`.
24926 * @polymerBehavior
24927 */
24928 Polymer.NeonAnimatableBehavior = {
24929
24930 properties: {
24931
24932 /**
24933 * Animation configuration. See README for more info.
24934 */
24935 animationConfig: {
24936 type: Object
24937 },
24938
24939 /**
24940 * Convenience property for setting an 'entry' animation. Do not set `anim ationConfig.entry`
24941 * manually if using this. The animated node is set to `this` if using thi s property.
24942 */
24943 entryAnimation: {
24944 observer: '_entryAnimationChanged',
24945 type: String
24946 },
24947
24948 /**
24949 * Convenience property for setting an 'exit' animation. Do not set `anima tionConfig.exit`
24950 * manually if using this. The animated node is set to `this` if using thi s property.
24951 */
24952 exitAnimation: {
24953 observer: '_exitAnimationChanged',
24954 type: String
24955 }
24956
24957 },
24958
24959 _entryAnimationChanged: function() {
24960 this.animationConfig = this.animationConfig || {};
24961 this.animationConfig['entry'] = [{
24962 name: this.entryAnimation,
24963 node: this
24964 }];
24965 },
24966
24967 _exitAnimationChanged: function() {
24968 this.animationConfig = this.animationConfig || {};
24969 this.animationConfig['exit'] = [{
24970 name: this.exitAnimation,
24971 node: this
24972 }];
24973 },
24974
24975 _copyProperties: function(config1, config2) {
24976 // shallowly copy properties from config2 to config1
24977 for (var property in config2) {
24978 config1[property] = config2[property];
24979 }
24980 },
24981
24982 _cloneConfig: function(config) {
24983 var clone = {
24984 isClone: true
24985 };
24986 this._copyProperties(clone, config);
24987 return clone;
24988 },
24989
24990 _getAnimationConfigRecursive: function(type, map, allConfigs) {
24991 if (!this.animationConfig) {
24992 return;
24993 }
24994
24995 if(this.animationConfig.value && typeof this.animationConfig.value === 'fu nction') {
24996 this._warn(this._logf('playAnimation', "Please put 'animationConfig' ins ide of your components 'properties' object instead of outside of it."));
24997 return;
24998 }
24999
25000 // type is optional
25001 var thisConfig;
25002 if (type) {
25003 thisConfig = this.animationConfig[type];
25004 } else {
25005 thisConfig = this.animationConfig;
25006 }
25007
25008 if (!Array.isArray(thisConfig)) {
25009 thisConfig = [thisConfig];
25010 }
25011
25012 // iterate animations and recurse to process configurations from child nod es
25013 if (thisConfig) {
25014 for (var config, index = 0; config = thisConfig[index]; index++) {
25015 if (config.animatable) {
25016 config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
25017 } else {
25018 if (config.id) {
25019 var cachedConfig = map[config.id];
25020 if (cachedConfig) {
25021 // merge configurations with the same id, making a clone lazily
25022 if (!cachedConfig.isClone) {
25023 map[config.id] = this._cloneConfig(cachedConfig)
25024 cachedConfig = map[config.id];
25025 }
25026 this._copyProperties(cachedConfig, config);
25027 } else {
25028 // put any configs with an id into a map
25029 map[config.id] = config;
25030 }
25031 } else {
25032 allConfigs.push(config);
25033 }
25034 }
25035 }
25036 }
25037 },
25038
25039 /**
25040 * An element implementing `Polymer.NeonAnimationRunnerBehavior` calls this method to configure
25041 * an animation with an optional type. Elements implementing `Polymer.NeonAn imatableBehavior`
25042 * should define the property `animationConfig`, which is either a configura tion object
25043 * or a map of animation type to array of configuration objects.
25044 */
25045 getAnimationConfig: function(type) {
25046 var map = {};
25047 var allConfigs = [];
25048 this._getAnimationConfigRecursive(type, map, allConfigs);
25049 // append the configurations saved in the map to the array
25050 for (var key in map) {
25051 allConfigs.push(map[key]);
25052 }
25053 return allConfigs;
25054 }
25055
25056 };
25057
25058 </script>
25059 <script>
25060
25061 /**
25062 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations.
25063 *
25064 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior
25065 */
25066 Polymer.NeonAnimationRunnerBehaviorImpl = {
25067
25068 _configureAnimations: function(configs) {
25069 var results = [];
25070 if (configs.length > 0) {
25071 for (var config, index = 0; config = configs[index]; index++) {
25072 var neonAnimation = document.createElement(config.name);
25073 // is this element actually a neon animation?
25074 if (neonAnimation.isNeonAnimation) {
25075 var result = null;
25076 // configuration or play could fail if polyfills aren't loaded
25077 try {
25078 result = neonAnimation.configure(config);
25079 // Check if we have an Effect rather than an Animation
25080 if (typeof result.cancel != 'function') {
25081 result = document.timeline.play(result);
25082 }
25083 } catch (e) {
25084 result = null;
25085 console.warn('Couldnt play', '(', config.name, ').', e);
25086 }
25087 if (result) {
25088 results.push({
25089 neonAnimation: neonAnimation,
25090 config: config,
25091 animation: result,
25092 });
25093 }
25094 } else {
25095 console.warn(this.is + ':', config.name, 'not found!');
25096 }
25097 }
25098 }
25099 return results;
25100 },
25101
25102 _shouldComplete: function(activeEntries) {
25103 var finished = true;
25104 for (var i = 0; i < activeEntries.length; i++) {
25105 if (activeEntries[i].animation.playState != 'finished') {
25106 finished = false;
25107 break;
25108 }
25109 }
25110 return finished;
25111 },
25112
25113 _complete: function(activeEntries) {
25114 for (var i = 0; i < activeEntries.length; i++) {
25115 activeEntries[i].neonAnimation.complete(activeEntries[i].config);
25116 }
25117 for (var i = 0; i < activeEntries.length; i++) {
25118 activeEntries[i].animation.cancel();
25119 }
25120 },
25121
25122 /**
25123 * Plays an animation with an optional `type`.
25124 * @param {string=} type
25125 * @param {!Object=} cookie
25126 */
25127 playAnimation: function(type, cookie) {
25128 var configs = this.getAnimationConfig(type);
25129 if (!configs) {
25130 return;
25131 }
25132 this._active = this._active || {};
25133 if (this._active[type]) {
25134 this._complete(this._active[type]);
25135 delete this._active[type];
25136 }
25137
25138 var activeEntries = this._configureAnimations(configs);
25139
25140 if (activeEntries.length == 0) {
25141 this.fire('neon-animation-finish', cookie, {bubbles: false});
25142 return;
25143 }
25144
25145 this._active[type] = activeEntries;
25146
25147 for (var i = 0; i < activeEntries.length; i++) {
25148 activeEntries[i].animation.onfinish = function() {
25149 if (this._shouldComplete(activeEntries)) {
25150 this._complete(activeEntries);
25151 delete this._active[type];
25152 this.fire('neon-animation-finish', cookie, {bubbles: false});
25153 }
25154 }.bind(this);
25155 }
25156 },
25157
25158 /**
25159 * Cancels the currently running animations.
25160 */
25161 cancelAnimation: function() {
25162 for (var k in this._animations) {
25163 this._animations[k].cancel();
25164 }
25165 this._animations = {};
25166 }
25167 };
25168
25169 /** @polymerBehavior Polymer.NeonAnimationRunnerBehavior */
25170 Polymer.NeonAnimationRunnerBehavior = [
25171 Polymer.NeonAnimatableBehavior,
25172 Polymer.NeonAnimationRunnerBehaviorImpl
25173 ];
25174 </script>
25175 <script>
25176
25177 /**
25178 Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to imple ment a Material Design
25179 dialog.
25180
25181 For example, if `<paper-dialog-impl>` implements this behavior:
25182
25183 <paper-dialog-impl>
25184 <h2>Header</h2>
25185 <div>Dialog body</div>
25186 <div class="buttons">
25187 <paper-button dialog-dismiss>Cancel</paper-button>
25188 <paper-button dialog-confirm>Accept</paper-button>
25189 </div>
25190 </paper-dialog-impl>
25191
25192 `paper-dialog-shared-styles.html` provide styles for a header, content area, and an action area for buttons.
25193 Use the `<h2>` tag for the header and the `buttons` class for the action area. Y ou can use the
25194 `paper-dialog-scrollable` element (in its own repository) if you need a scrollin g content area.
25195
25196 Use the `dialog-dismiss` and `dialog-confirm` attributes on interactive controls to close the
25197 dialog. If the user dismisses the dialog with `dialog-confirm`, the `closingReas on` will update
25198 to include `confirmed: true`.
25199
25200 ### Accessibility
25201
25202 This element has `role="dialog"` by default. Depending on the context, it may be more appropriate
25203 to override this attribute with `role="alertdialog"`.
25204
25205 If `modal` is set, the element will prevent the focus from exiting the element.
25206 It will also ensure that focus remains in the dialog.
25207
25208 @hero hero.svg
25209 @demo demo/index.html
25210 @polymerBehavior Polymer.PaperDialogBehavior
25211 */
25212
25213 Polymer.PaperDialogBehaviorImpl = {
25214
25215 hostAttributes: {
25216 'role': 'dialog',
25217 'tabindex': '-1'
25218 },
25219
25220 properties: {
25221
25222 /**
25223 * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-canc el-on-esc-key` and `with-backdrop`.
25224 */
25225 modal: {
25226 type: Boolean,
25227 value: false
25228 }
25229
25230 },
25231
25232 observers: [
25233 '_modalChanged(modal, _readied)'
25234 ],
25235
25236 listeners: {
25237 'tap': '_onDialogClick'
25238 },
25239
25240 ready: function () {
25241 // Only now these properties can be read.
25242 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
25243 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
25244 this.__prevWithBackdrop = this.withBackdrop;
25245 },
25246
25247 _modalChanged: function(modal, readied) {
25248 // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop .
25249 // We need to wait for the element to be ready before we can read the
25250 // properties values.
25251 if (!readied) {
25252 return;
25253 }
25254
25255 if (modal) {
25256 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
25257 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
25258 this.__prevWithBackdrop = this.withBackdrop;
25259 this.noCancelOnOutsideClick = true;
25260 this.noCancelOnEscKey = true;
25261 this.withBackdrop = true;
25262 } else {
25263 // If the value was changed to false, let it false.
25264 this.noCancelOnOutsideClick = this.noCancelOnOutsideClick &&
25265 this.__prevNoCancelOnOutsideClick;
25266 this.noCancelOnEscKey = this.noCancelOnEscKey &&
25267 this.__prevNoCancelOnEscKey;
25268 this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop;
25269 }
25270 },
25271
25272 _updateClosingReasonConfirmed: function(confirmed) {
25273 this.closingReason = this.closingReason || {};
25274 this.closingReason.confirmed = confirmed;
25275 },
25276
25277 /**
25278 * Will dismiss the dialog if user clicked on an element with dialog-dismiss
25279 * or dialog-confirm attribute.
25280 */
25281 _onDialogClick: function(event) {
25282 // Search for the element with dialog-confirm or dialog-dismiss,
25283 // from the root target until this (excluded).
25284 var path = Polymer.dom(event).path;
25285 for (var i = 0; i < path.indexOf(this); i++) {
25286 var target = path[i];
25287 if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || tar get.hasAttribute('dialog-confirm'))) {
25288 this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm '));
25289 this.close();
25290 event.stopPropagation();
25291 break;
25292 }
25293 }
25294 }
25295
25296 };
25297
25298 /** @polymerBehavior */
25299 Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialo gBehaviorImpl];
25300
25301 </script>
25302
25303
25304 <dom-module id="paper-dialog-shared-styles" assetpath="/res/imp/bower_components /paper-dialog-behavior/">
25305 <template>
25306 <style>
25307 :host {
25308 display: block;
25309 margin: 24px 40px;
25310
25311 background: var(--paper-dialog-background-color, --primary-background-co lor);
25312 color: var(--paper-dialog-color, --primary-text-color);
25313
25314 @apply(--paper-font-body1);
25315 @apply(--shadow-elevation-16dp);
25316 @apply(--paper-dialog);
25317 }
25318
25319 :host > ::content > * {
25320 margin-top: 20px;
25321 padding: 0 24px;
25322 }
25323
25324 :host > ::content > .no-padding {
25325 padding: 0;
25326 }
25327
25328 :host > ::content > *:first-child {
25329 margin-top: 24px;
25330 }
25331
25332 :host > ::content > *:last-child {
25333 margin-bottom: 24px;
25334 }
25335
25336 :host > ::content h2 {
25337 position: relative;
25338 margin: 0;
25339 @apply(--paper-font-title);
25340
25341 @apply(--paper-dialog-title);
25342 }
25343
25344 :host > ::content .buttons {
25345 position: relative;
25346 padding: 8px 8px 8px 24px;
25347 margin: 0;
25348
25349 color: var(--paper-dialog-button-color, --primary-color);
25350
25351 @apply(--layout-horizontal);
25352 @apply(--layout-end-justified);
25353 }
25354 </style>
25355 </template>
25356 </dom-module>
25357
25358
25359 <dom-module id="paper-dialog" assetpath="/res/imp/bower_components/paper-dialog/ ">
25360 <template>
25361 <style include="paper-dialog-shared-styles"></style>
25362 <content></content>
25363 </template>
25364 </dom-module>
25365
25366 <script>
25367
25368 (function() {
25369
25370 Polymer({
25371
25372 is: 'paper-dialog',
25373
25374 behaviors: [
25375 Polymer.PaperDialogBehavior,
25376 Polymer.NeonAnimationRunnerBehavior
25377 ],
25378
25379 listeners: {
25380 'neon-animation-finish': '_onNeonAnimationFinish'
25381 },
25382
25383 _renderOpened: function() {
25384 this.cancelAnimation();
25385 this.playAnimation('entry');
25386 },
25387
25388 _renderClosed: function() {
25389 this.cancelAnimation();
25390 this.playAnimation('exit');
25391 },
25392
25393 _onNeonAnimationFinish: function() {
25394 if (this.opened) {
25395 this._finishRenderOpened();
25396 } else {
25397 this._finishRenderClosed();
25398 }
25399 }
25400
25401 });
25402
25403 })();
25404
25405 </script>
25406 <script>
25407
25408 /**
24899 * `Polymer.IronMenuBehavior` implements accessible menu behavior. 25409 * `Polymer.IronMenuBehavior` implements accessible menu behavior.
24900 * 25410 *
24901 * @demo demo/index.html 25411 * @demo demo/index.html
24902 * @polymerBehavior Polymer.IronMenuBehavior 25412 * @polymerBehavior Polymer.IronMenuBehavior
24903 */ 25413 */
24904 Polymer.IronMenuBehaviorImpl = { 25414 Polymer.IronMenuBehaviorImpl = {
24905 25415
24906 properties: { 25416 properties: {
24907 25417
24908 /** 25418 /**
(...skipping 1354 matching lines...) Expand 10 before | Expand all | Expand 10 after
26263 margin-bottom: 5px; 26773 margin-bottom: 5px;
26264 } 26774 }
26265 td, th { 26775 td, th {
26266 border: 1px solid #BBB; 26776 border: 1px solid #BBB;
26267 padding: 5px; 26777 padding: 5px;
26268 } 26778 }
26269 26779
26270 .quarantined, .failed_task { 26780 .quarantined, .failed_task {
26271 background-color: #ffdddd; 26781 background-color: #ffdddd;
26272 } 26782 }
26273 .dead { 26783 .dead, .bot_died {
26274 background-color: #cccccc; 26784 background-color: #cccccc;
26275 } 26785 }
26276 26786
26277 .message { 26787 .message {
26278 white-space: pre-line; 26788 white-space: pre-line;
26279 font-family: monospace; 26789 font-family: monospace;
26280 } 26790 }
26281 26791
26282 .bot_state { 26792 .bot_state {
26283 white-space: pre; 26793 white-space: pre;
(...skipping 22 matching lines...) Expand all
26306 } 26816 }
26307 26817
26308 paper-tab.iron-selected { 26818 paper-tab.iron-selected {
26309 background-color: #A6CEE3; 26819 background-color: #A6CEE3;
26310 border: 3px solid #1F78B4; 26820 border: 3px solid #1F78B4;
26311 color: #000; 26821 color: #000;
26312 font-weight: bold; 26822 font-weight: bold;
26313 text-decoration: underline; 26823 text-decoration: underline;
26314 } 26824 }
26315 26825
26826 paper-dialog {
26827 border-radius: 6px;
26828 }
26829
26316 </style> 26830 </style>
26317 26831
26318 <url-param name="id" value="{{bot_id}}"> 26832 <url-param name="id" value="{{bot_id}}">
26319 </url-param> 26833 </url-param>
26320 <url-param name="show_all_events" value="{{_show_all}}"> 26834 <url-param name="show_all_events" value="{{_show_all}}">
26321 </url-param> 26835 </url-param>
26322 <url-param name="selected" value="{{_selected}}"> 26836 <url-param name="selected" value="{{_selected}}">
26323 </url-param> 26837 </url-param>
26324 <url-param name="show_state" value="{{_show_state}}"> 26838 <url-param name="show_state" value="{{_show_state}}">
26325 </url-param> 26839 </url-param>
26326 26840
26327 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Bot Page"> 26841 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Bot Page">
26328 26842
26329 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 26843 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
26330 26844
26331 <div hidden$="[[_not(_signed_in)]]"> 26845 <div hidden$="[[_not(_signed_in)]]">
26332 26846
26333 <bot-page-data auth_headers="[[_auth_headers]]" bot_id="[[bot_id]]" bot= "{{_bot}}" busy="{{_busy}}" events="{{_events}}" tasks="{{_tasks}}"> 26847 <bot-page-data id="data" auth_headers="[[_auth_headers]]" bot_id="[[bot_ id]]" bot="{{_bot}}" busy="{{_busy}}" events="{{_events}}" tasks="{{_tasks}}">
26334 </bot-page-data> 26848 </bot-page-data>
26335 26849
26336 <div class="header horizontal layout"> 26850 <div class="header horizontal layout">
26337 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input> 26851 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input>
26338 <button> 26852 <button on-click="_refresh">
26339 <iron-icon class="refresh" icon="icons:refresh"></iron-icon> 26853 <iron-icon class="refresh" icon="icons:refresh"></iron-icon>
26340 </button> 26854 </button>
26341 </div> 26855 </div>
26342 26856
26343 <div> 26857 <div>
26344 <table> 26858 <table>
26345 <tbody><tr class$="[[_isDead(_bot)]]"> 26859 <tbody><tr class$="[[_isDead(_bot)]]">
26346 <td>Last Seen</td> 26860 <td>Last Seen</td>
26347 <td title="[[_bot.human_last_seen_ts]]"> 26861 <td title="[[_bot.human_last_seen_ts]]">
26348 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> 26862 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td>
26349 <td> 26863 <td>
26350 26864
26351 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> 26865 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]">
26352 <button class="raised"> 26866 <button class="raised" on-click="_promptShutdown">
26353 Shut Down Gracefully 26867 Shut Down Gracefully
26354 </button> 26868 </button>
26355 </template> 26869 </template>
26356 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> 26870 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]">
26357 <button class="raised"> 26871 <button class="raised" on-click="_promptDelete">
26358 Delete 26872 Delete
26359 </button> 26873 </button>
26360 </template> 26874 </template>
26361 </td> 26875 </td>
26362 </tr> 26876 </tr>
26363 <template is="dom-if" if="[[_bot.quarantined]]"> 26877 <template is="dom-if" if="[[_bot.quarantined]]">
26364 <tr class="quarantined"> 26878 <tr class="quarantined">
26365 <td>Quarantined</td> 26879 <td>Quarantined</td>
26366 <td colspan="2">[[_quarantineMessage(_bot)]]</td> 26880 <td colspan="2">[[_quarantineMessage(_bot)]]</td>
26367 </tr> 26881 </tr>
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
26450 <thead> 26964 <thead>
26451 <tr> 26965 <tr>
26452 <th>Task</th> 26966 <th>Task</th>
26453 <th>Started</th> 26967 <th>Started</th>
26454 <th>Duration</th> 26968 <th>Duration</th>
26455 <th>Result</th> 26969 <th>Result</th>
26456 </tr> 26970 </tr>
26457 </thead> 26971 </thead>
26458 <tbody> 26972 <tbody>
26459 <template is="dom-repeat" items="{{_tasks}}" as="task"> 26973 <template is="dom-repeat" items="{{_tasks}}" as="task">
26460 <tr> 26974 <tr class$="[[_taskClass(task)]]">
26461 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td> 26975 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td>
26462 <td>[[task.human_started_ts]]</td> 26976 <td>[[task.human_started_ts]]</td>
26463 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td> 26977 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td>
26464 <td>[[task.state]]</td> 26978 <td>[[task.state]]</td>
26465 </tr> 26979 </tr>
26466 </template> 26980 </template>
26467 </tbody> 26981 </tbody>
26468 </table> 26982 </table>
26469 </template> 26983 </template>
26470 26984
(...skipping 18 matching lines...) Expand all
26489 <td> 27003 <td>
26490 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a> 27004 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a>
26491 </td> 27005 </td>
26492 </tr> 27006 </tr>
26493 </template> 27007 </template>
26494 </tbody> 27008 </tbody>
26495 </table> 27009 </table>
26496 </template> 27010 </template>
26497 </div> 27011 </div>
26498 27012
27013 </swarming-app>
26499 27014
26500 </swarming-app> 27015 <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed">
27016 <h2>Are you sure?</h2>
27017 <div>Are you sure you want to [[_dialogPrompt]]?</div>
27018 <div class="buttons">
27019 <paper-button dialog-dismiss="" autofocus="">No</paper-button>
27020 <paper-button dialog-confirm="">Yes</paper-button>
27021 </div>
27022 </paper-dialog>
27023
27024 <error-toast></error-toast>
26501 27025
26502 </template> 27026 </template>
26503 <script> 27027 <script>
26504 (function(){ 27028 (function(){
26505 27029
26506 27030
26507 Polymer({ 27031 Polymer({
26508 is: 'bot-page', 27032 is: 'bot-page',
26509 27033
26510 behaviors: [ 27034 behaviors: [
26511 SwarmingBehaviors.BotPageBehavior, 27035 SwarmingBehaviors.BotPageBehavior,
26512 ], 27036 ],
26513 27037
26514 properties: { 27038 properties: {
26515 bot_id: { 27039 bot_id: {
26516 type: String, 27040 type: String,
26517 }, 27041 },
26518 client_id: { 27042 client_id: {
26519 type: String, 27043 type: String,
26520 }, 27044 },
26521 27045
27046 _auth_headers: {
27047 type: Object,
27048 },
26522 _bot: { 27049 _bot: {
26523 type: Object, 27050 type: Object,
26524 }, 27051 },
27052 _dialogPrompt: {
27053 type: String,
27054 value: "",
27055 },
26525 _selected: { 27056 _selected: {
26526 type: Number, 27057 type: Number,
26527 }, 27058 },
26528 _show_all: { 27059 _show_all: {
26529 type: Boolean, 27060 type: Boolean,
26530 }, 27061 },
26531 _show_state: { 27062 _show_state: {
26532 type: Boolean, 27063 type: Boolean,
26533 } 27064 }
26534 }, 27065 },
(...skipping 10 matching lines...) Expand all
26545 return bot && !bot.is_dead && permissions.terminate_bot; 27076 return bot && !bot.is_dead && permissions.terminate_bot;
26546 }, 27077 },
26547 27078
26548 _concat: function(arr) { 27079 _concat: function(arr) {
26549 if (!arr) { 27080 if (!arr) {
26550 return ""; 27081 return "";
26551 } 27082 }
26552 return arr.join(" | "); 27083 return arr.join(" | ");
26553 }, 27084 },
26554 27085
27086 _deleteBot: function() {
27087 this._postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/delete",
27088 "Deleting "+this.bot_id, this._auth_headers);
27089 },
27090
26555 _eventList(events, showAll) { 27091 _eventList(events, showAll) {
26556 if (!events) { 27092 if (!events) {
26557 return []; 27093 return [];
26558 } 27094 }
26559 return events.filter(function(e){ 27095 return events.filter(function(e){
26560 return showAll || e.message; 27096 return showAll || e.message;
26561 }); 27097 });
26562 }, 27098 },
26563 27099
26564 _isDead(bot){ 27100 _isDead(bot){
(...skipping 16 matching lines...) Expand all
26581 return 1; 27117 return 1;
26582 } 27118 }
26583 return 1 + arr.length; 27119 return 1 + arr.length;
26584 }, 27120 },
26585 27121
26586 _prettyPrint: function(obj) { 27122 _prettyPrint: function(obj) {
26587 obj = obj || {}; 27123 obj = obj || {};
26588 return JSON.stringify(obj, null, 2); 27124 return JSON.stringify(obj, null, 2);
26589 }, 27125 },
26590 27126
27127 _promptClosed: function(e) {
27128 if (e.detail.confirmed) {
27129 if (this._dialogPrompt.startsWith("shut down")) {
27130 this._shutdownBot();
27131 } else {
27132 this._deleteBot();
27133 }
27134 }
27135 },
27136
27137 _promptDelete: function() {
27138 this.set("_dialogPrompt", "delete "+this.bot_id);
27139 this.$.prompt.open();
27140 },
27141
27142 _promptShutdown: function() {
27143 this.set("_dialogPrompt", "shut down "+this.bot_id);
27144 this.$.prompt.open();
27145 },
27146
26591 _quarantineMessage: function(bot) { 27147 _quarantineMessage: function(bot) {
26592 if (bot && bot.quarantined) { 27148 if (bot && bot.quarantined) {
26593 var msg = bot.state.quarantined; 27149 var msg = bot.state.quarantined;
26594 // Sometimes, the quarantined message is actually in "error". This 27150 // Sometimes, the quarantined message is actually in "error". This
26595 // happens when the bot code has thrown an exception. 27151 // happens when the bot code has thrown an exception.
26596 if (msg === undefined || msg === "true" || msg === true) { 27152 if (msg === undefined || msg === "true" || msg === true) {
26597 msg = this._attribute(bot, "error"); 27153 msg = this._attribute(bot, "error");
26598 } 27154 }
26599 return msg || "True"; 27155 return msg || "True";
26600 } 27156 }
26601 return ""; 27157 return "";
26602 }, 27158 },
26603 27159
27160 _refresh: function() {
27161 this.$.data.request();
27162 },
27163
26604 _shorten: function(str, length) { 27164 _shorten: function(str, length) {
26605 if (!str || ! length) { 27165 if (!str || ! length) {
26606 return ""; 27166 return "";
26607 } 27167 }
26608 return str.substring(0, length); 27168 return str.substring(0, length);
26609 }, 27169 },
26610 27170
27171 _shutdownBot: function() {
27172 this._postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/terminate" ,
27173 "Shutting down "+this.bot_id, this._auth_headers);
27174 },
27175
26611 _task: function(bot) { 27176 _task: function(bot) {
26612 return (bot && bot.task_id) || "idle"; 27177 return (bot && bot.task_id) || "idle";
26613 }, 27178 },
26614 27179
27180 _taskClass: function(task) {
27181 if (task && task.internal_failure) {
27182 return "bot_died";
27183 }
27184 if (task && task.failure) {
27185 return "failed_task";
27186 }
27187 return "";
27188 },
27189
26615 _taskLink: function(task_id) { 27190 _taskLink: function(task_id) {
26616 // TODO(kjlubick): Migrate this to /newui/ when ready 27191 // TODO(kjlubick): Migrate this to /newui/ when ready
26617 if (task_id) { 27192 if (task_id) {
26618 return "/user/task/" + task_id; 27193 return "/user/task/" + task_id;
26619 } 27194 }
26620 return undefined; 27195 return undefined;
26621 }, 27196 },
26622 27197
26623 _toggleState: function() { 27198 _toggleState: function() {
26624 this.set("_show_state", !this._show_state); 27199 this.set("_show_state", !this._show_state);
26625 } 27200 }
26626 27201
26627 }); 27202 });
26628 })(); 27203 })();
26629 </script> 27204 </script>
26630 </dom-module></div></body></html> 27205 </dom-module></div></body></html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698