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

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 nits 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
« no previous file with comments | « no previous file | appengine/swarming/elements/build/js/js.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 23948 matching lines...) Expand 10 before | Expand all | Expand 10 after
23959 Fired when the animation finishes. 23959 Fired when the animation finishes.
23960 This is useful if you want to wait until 23960 This is useful if you want to wait until
23961 the ripple animation finishes to perform some action. 23961 the ripple animation finishes to perform some action.
23962 23962
23963 @event transitionend 23963 @event transitionend
23964 Event param: {{node: Object}} detail Contains the animated node. 23964 Event param: {{node: Object}} detail Contains the animated node.
23965 */ 23965 */
23966 }); 23966 });
23967 </script> 23967 </script>
23968 </dom-module> 23968 </dom-module>
23969 <dom-module id="error-toast" assetpath="/res/imp/common/">
23970 <template>
23971 <paper-toast id="toast"></paper-toast>
23972 </template>
23973 </dom-module>
23974
23975 <script>
23976 Polymer({
23977 is: "error-toast",
23978
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 1346 matching lines...) Expand 10 before | Expand all | Expand 10 after
26255 max-height: 50px; 26752 max-height: 50px;
26256 width: initial; 26753 width: initial;
26257 height: initial; 26754 height: initial;
26258 } 26755 }
26259 26756
26260 table { 26757 table {
26261 border-collapse: collapse; 26758 border-collapse: collapse;
26262 margin-left: 5px; 26759 margin-left: 5px;
26263 margin-bottom: 5px; 26760 margin-bottom: 5px;
26264 } 26761 }
26265 td, th { 26762 td,
26763 th {
26266 border: 1px solid #BBB; 26764 border: 1px solid #BBB;
26267 padding: 5px; 26765 padding: 5px;
26268 } 26766 }
26269 26767
26270 .quarantined, .failed_task { 26768 .quarantined,
26769 .failed_task {
26271 background-color: #ffdddd; 26770 background-color: #ffdddd;
26272 } 26771 }
26273 .dead { 26772 .dead,
26773 .bot_died {
26274 background-color: #cccccc; 26774 background-color: #cccccc;
26275 } 26775 }
26276 26776
26277 .message { 26777 .message {
26278 white-space: pre-line; 26778 white-space: pre-line;
26279 font-family: monospace; 26779 font-family: monospace;
26280 } 26780 }
26281 26781
26282 .bot_state { 26782 .bot_state {
26283 white-space: pre; 26783 white-space: pre;
26284 font-family: monospace; 26784 font-family: monospace;
26285 margin-bottom: 10px; 26785 margin-bottom: 10px;
26286 } 26786 }
26287 26787
26288 .tabs { 26788 .tabs {
26289 background-color: #1F78B4; 26789 background-color: #1F78B4;
26290 color: #fff; 26790 color: #fff;
26291 max-width: 600px; 26791 max-width: 600px;
26292 --paper-checkbox-label-color: #fff; 26792 --paper-checkbox-label-color: #fff;
26293 margin-left: 5px; 26793 margin-left: 5px;
26294 } 26794 }
26295 26795
26296 .tasks_table, .events_table { 26796 .tasks_table,
26797 .events_table {
26297 border: 3px solid #1F78B4; 26798 border: 3px solid #1F78B4;
26298 } 26799 }
26299 26800
26300 paper-checkbox { 26801 paper-checkbox {
26301 --paper-checkbox-label-color: #fff; 26802 --paper-checkbox-label-color: #fff;
26302 --paper-checkbox-checked-color: #fff; 26803 --paper-checkbox-checked-color: #fff;
26303 --paper-checkbox-checkmark-color: #000; 26804 --paper-checkbox-checkmark-color: #000;
26304 --paper-checkbox-unchecked-color: #fff; 26805 --paper-checkbox-unchecked-color: #fff;
26305 padding: 3px; 26806 padding: 3px;
26306 } 26807 }
26307 26808
26308 paper-tab.iron-selected { 26809 paper-tab.iron-selected {
26309 background-color: #A6CEE3; 26810 background-color: #A6CEE3;
26310 border: 3px solid #1F78B4; 26811 border: 3px solid #1F78B4;
26311 color: #000; 26812 color: #000;
26312 font-weight: bold; 26813 font-weight: bold;
26313 text-decoration: underline; 26814 text-decoration: underline;
26314 } 26815 }
26315 26816
26817 paper-dialog {
26818 border-radius: 6px;
26819 }
26820
26316 </style> 26821 </style>
26317 26822
26318 <url-param name="id" value="{{bot_id}}"> 26823 <url-param name="id" value="{{bot_id}}">
26319 </url-param> 26824 </url-param>
26320 <url-param name="show_all_events" value="{{_show_all}}"> 26825 <url-param name="show_all_events" value="{{_show_all}}">
26321 </url-param> 26826 </url-param>
26322 <url-param name="selected" value="{{_selected}}"> 26827 <url-param name="selected" value="{{_selected}}">
26323 </url-param> 26828 </url-param>
26324 <url-param name="show_state" value="{{_show_state}}"> 26829 <url-param name="show_state" value="{{_show_state}}">
26325 </url-param> 26830 </url-param>
26326 26831
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"> 26832 <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 26833
26329 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 26834 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
26330 26835
26331 <div hidden$="[[_not(_signed_in)]]"> 26836 <div hidden$="[[_not(_signed_in)]]">
26332 26837
26333 <bot-page-data auth_headers="[[_auth_headers]]" bot_id="[[bot_id]]" bot= "{{_bot}}" busy="{{_busy}}" events="{{_events}}" tasks="{{_tasks}}"> 26838 <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> 26839 </bot-page-data>
26335 26840
26336 <div class="header horizontal layout"> 26841 <div class="header horizontal layout">
26337 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input> 26842 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input>
26338 <button> 26843 <button on-click="_refresh">
26339 <iron-icon class="refresh" icon="icons:refresh"></iron-icon> 26844 <iron-icon class="refresh" icon="icons:refresh"></iron-icon>
26340 </button> 26845 </button>
26341 </div> 26846 </div>
26342 26847
26343 <div> 26848 <div>
26344 <table> 26849 <table>
26345 <tbody><tr class$="[[_isDead(_bot)]]"> 26850 <tbody><tr class$="[[_isDead(_bot)]]">
26346 <td>Last Seen</td> 26851 <td>Last Seen</td>
26347 <td title="[[_bot.human_last_seen_ts]]"> 26852 <td title="[[_bot.human_last_seen_ts]]">
26348 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> 26853 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td>
26349 <td> 26854 <td>
26350 26855
26351 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> 26856 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]">
26352 <button class="raised"> 26857 <button class="raised" on-click="_promptShutdown">
26353 Shut Down Gracefully 26858 Shut Down Gracefully
26354 </button> 26859 </button>
26355 </template> 26860 </template>
26356 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> 26861 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]">
26357 <button class="raised"> 26862 <button class="raised" on-click="_promptDelete">
26358 Delete 26863 Delete
26359 </button> 26864 </button>
26360 </template> 26865 </template>
26361 </td> 26866 </td>
26362 </tr> 26867 </tr>
26363 <template is="dom-if" if="[[_bot.quarantined]]"> 26868 <template is="dom-if" if="[[_bot.quarantined]]">
26364 <tr class="quarantined"> 26869 <tr class="quarantined">
26365 <td>Quarantined</td> 26870 <td>Quarantined</td>
26366 <td colspan="2">[[_quarantineMessage(_bot)]]</td> 26871 <td colspan="2">[[_quarantineMessage(_bot)]]</td>
26367 </tr> 26872 </tr>
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
26450 <thead> 26955 <thead>
26451 <tr> 26956 <tr>
26452 <th>Task</th> 26957 <th>Task</th>
26453 <th>Started</th> 26958 <th>Started</th>
26454 <th>Duration</th> 26959 <th>Duration</th>
26455 <th>Result</th> 26960 <th>Result</th>
26456 </tr> 26961 </tr>
26457 </thead> 26962 </thead>
26458 <tbody> 26963 <tbody>
26459 <template is="dom-repeat" items="{{_tasks}}" as="task"> 26964 <template is="dom-repeat" items="{{_tasks}}" as="task">
26460 <tr> 26965 <tr class$="[[_taskClass(task)]]">
26461 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td> 26966 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td>
26462 <td>[[task.human_started_ts]]</td> 26967 <td>[[task.human_started_ts]]</td>
26463 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td> 26968 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td>
26464 <td>[[task.state]]</td> 26969 <td>[[task.state]]</td>
26465 </tr> 26970 </tr>
26466 </template> 26971 </template>
26467 </tbody> 26972 </tbody>
26468 </table> 26973 </table>
26469 </template> 26974 </template>
26470 26975
(...skipping 18 matching lines...) Expand all
26489 <td> 26994 <td>
26490 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a> 26995 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a>
26491 </td> 26996 </td>
26492 </tr> 26997 </tr>
26493 </template> 26998 </template>
26494 </tbody> 26999 </tbody>
26495 </table> 27000 </table>
26496 </template> 27001 </template>
26497 </div> 27002 </div>
26498 27003
27004 </swarming-app>
26499 27005
26500 </swarming-app> 27006 <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed">
27007 <h2>Are you sure?</h2>
27008 <div>Are you sure you want to [[_dialogPrompt]]?</div>
27009 <div class="buttons">
27010 <paper-button dialog-dismiss="" autofocus="">No</paper-button>
27011 <paper-button dialog-confirm="">Yes</paper-button>
27012 </div>
27013 </paper-dialog>
27014
27015 <error-toast></error-toast>
26501 27016
26502 </template> 27017 </template>
26503 <script> 27018 <script>
26504 (function(){ 27019 (function(){
26505 27020
26506 27021
26507 Polymer({ 27022 Polymer({
26508 is: 'bot-page', 27023 is: 'bot-page',
26509 27024
26510 behaviors: [ 27025 behaviors: [
26511 SwarmingBehaviors.BotPageBehavior, 27026 SwarmingBehaviors.BotPageBehavior,
26512 ], 27027 ],
26513 27028
26514 properties: { 27029 properties: {
26515 bot_id: { 27030 bot_id: {
26516 type: String, 27031 type: String,
26517 }, 27032 },
26518 client_id: { 27033 client_id: {
26519 type: String, 27034 type: String,
26520 }, 27035 },
26521 27036
27037 _auth_headers: {
27038 type: Object,
27039 },
26522 _bot: { 27040 _bot: {
26523 type: Object, 27041 type: Object,
26524 }, 27042 },
27043 _dialogPrompt: {
27044 type: String,
27045 value: "",
27046 },
26525 _selected: { 27047 _selected: {
26526 type: Number, 27048 type: Number,
26527 }, 27049 },
26528 _show_all: { 27050 _show_all: {
26529 type: Boolean, 27051 type: Boolean,
26530 }, 27052 },
26531 _show_state: { 27053 _show_state: {
26532 type: Boolean, 27054 type: Boolean,
26533 } 27055 }
26534 }, 27056 },
(...skipping 10 matching lines...) Expand all
26545 return bot && !bot.is_dead && permissions.terminate_bot; 27067 return bot && !bot.is_dead && permissions.terminate_bot;
26546 }, 27068 },
26547 27069
26548 _concat: function(arr) { 27070 _concat: function(arr) {
26549 if (!arr) { 27071 if (!arr) {
26550 return ""; 27072 return "";
26551 } 27073 }
26552 return arr.join(" | "); 27074 return arr.join(" | ");
26553 }, 27075 },
26554 27076
27077 _deleteBot: function() {
27078 swarming.postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/delete" ,
27079 "Deleting "+this.bot_id, this._auth_headers);
27080 },
27081
26555 _eventList(events, showAll) { 27082 _eventList(events, showAll) {
26556 if (!events) { 27083 if (!events) {
26557 return []; 27084 return [];
26558 } 27085 }
26559 return events.filter(function(e){ 27086 return events.filter(function(e){
26560 return showAll || e.message; 27087 return showAll || e.message;
26561 }); 27088 });
26562 }, 27089 },
26563 27090
26564 _isDead(bot){ 27091 _isDead(bot){
(...skipping 16 matching lines...) Expand all
26581 return 1; 27108 return 1;
26582 } 27109 }
26583 return 1 + arr.length; 27110 return 1 + arr.length;
26584 }, 27111 },
26585 27112
26586 _prettyPrint: function(obj) { 27113 _prettyPrint: function(obj) {
26587 obj = obj || {}; 27114 obj = obj || {};
26588 return JSON.stringify(obj, null, 2); 27115 return JSON.stringify(obj, null, 2);
26589 }, 27116 },
26590 27117
27118 _promptClosed: function(e) {
27119 if (e.detail.confirmed) {
27120 if (this._dialogPrompt.startsWith("shut down")) {
27121 this._shutdownBot();
27122 } else {
27123 this._deleteBot();
27124 }
27125 }
27126 },
27127
27128 _promptDelete: function() {
27129 this.set("_dialogPrompt", "delete "+this.bot_id);
27130 this.$.prompt.open();
27131 },
27132
27133 _promptShutdown: function() {
27134 this.set("_dialogPrompt", "shut down "+this.bot_id);
27135 this.$.prompt.open();
27136 },
27137
26591 _quarantineMessage: function(bot) { 27138 _quarantineMessage: function(bot) {
26592 if (bot && bot.quarantined) { 27139 if (bot && bot.quarantined) {
26593 var msg = bot.state.quarantined; 27140 var msg = bot.state.quarantined;
26594 // Sometimes, the quarantined message is actually in "error". This 27141 // Sometimes, the quarantined message is actually in "error". This
26595 // happens when the bot code has thrown an exception. 27142 // happens when the bot code has thrown an exception.
26596 if (msg === undefined || msg === "true" || msg === true) { 27143 if (msg === undefined || msg === "true" || msg === true) {
26597 msg = this._attribute(bot, "error"); 27144 msg = this._attribute(bot, "error");
26598 } 27145 }
26599 return msg || "True"; 27146 return msg || "True";
26600 } 27147 }
26601 return ""; 27148 return "";
26602 }, 27149 },
26603 27150
27151 _refresh: function() {
27152 this.$.data.request();
27153 },
27154
26604 _shorten: function(str, length) { 27155 _shorten: function(str, length) {
26605 if (!str || ! length) { 27156 if (!str || ! length) {
26606 return ""; 27157 return "";
26607 } 27158 }
26608 return str.substring(0, length); 27159 return str.substring(0, length);
26609 }, 27160 },
26610 27161
27162 _shutdownBot: function() {
27163 swarming.postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/termina te",
27164 "Shutting down "+this.bot_id, this._auth_headers);
27165 },
27166
26611 _task: function(bot) { 27167 _task: function(bot) {
26612 return (bot && bot.task_id) || "idle"; 27168 return (bot && bot.task_id) || "idle";
26613 }, 27169 },
26614 27170
27171 _taskClass: function(task) {
27172 if (task && task.internal_failure) {
27173 return "bot_died";
27174 }
27175 if (task && task.failure) {
27176 return "failed_task";
27177 }
27178 return "";
27179 },
27180
26615 _taskLink: function(task_id) { 27181 _taskLink: function(task_id) {
26616 // TODO(kjlubick): Migrate this to /newui/ when ready 27182 // TODO(kjlubick): Migrate this to /newui/ when ready
26617 if (task_id) { 27183 if (task_id) {
26618 return "/user/task/" + task_id; 27184 return "/user/task/" + task_id;
26619 } 27185 }
26620 return undefined; 27186 return undefined;
26621 }, 27187 },
26622 27188
26623 _toggleState: function() { 27189 _toggleState: function() {
26624 this.set("_show_state", !this._show_state); 27190 this.set("_show_state", !this._show_state);
26625 } 27191 }
26626 27192
26627 }); 27193 });
26628 })(); 27194 })();
26629 </script> 27195 </script>
26630 </dom-module></div></body></html> 27196 </dom-module></div></body></html>
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/elements/build/js/js.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698