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

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

Powered by Google App Engine
This is Rietveld 408576698