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

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

Issue 2306103002: Add aliases to bot-page and refactor duplicated code (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@fix-buttons
Patch Set: rebase again 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 23256 matching lines...) Expand 10 before | Expand all | Expand 10 after
23267 // pMap will have a list of columns to available values (primary key 23267 // pMap will have a list of columns to available values (primary key
23268 // to secondary values). This includes bot dimensions, but also 23268 // to secondary values). This includes bot dimensions, but also
23269 // includes state like disk_space, quarantined, busy, etc. 23269 // includes state like disk_space, quarantined, busy, etc.
23270 dimensions = dimensions.bots_dimensions; 23270 dimensions = dimensions.bots_dimensions;
23271 23271
23272 var pMap = {}; 23272 var pMap = {};
23273 dimensions.forEach(function(d){ 23273 dimensions.forEach(function(d){
23274 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) { 23274 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(d.key) === -1) {
23275 // value is an array of all seen values for the dimension d.key 23275 // value is an array of all seen values for the dimension d.key
23276 pMap[d.key] = d.value; 23276 pMap[d.key] = d.value;
23277 } else if (d.key === "gpu") {
23278 var gpus = [];
23279 d.value.forEach(function(g){
23280 var alias = swarming.alias.gpu(g);
23281 if (alias !== "unknown") {
23282 gpus.push(swarming.alias.apply(g, alias));
23283 } else {
23284 gpus.push(g);
23285 }
23286 }.bind(this));
23287 pMap["gpu"] = gpus;
23288 } else if (d.key === "device_type") {
23289 var devs = [];
23290 d.value.forEach(function(dt){
23291 var alias = swarming.alias.android(dt);
23292 if (alias !== "unknown") {
23293 devs.push(swarming.alias.apply(dt, alias));
23294 } else {
23295 devs.push(dt);
23296 }
23297 }.bind(this));
23298 pMap["device_type"] = devs;
23299 } else { 23277 } else {
23300 console.log("Unknown alias type: ", d); 23278 var aliased = [];
23279 d.value.forEach(function(value){
23280 aliased.push(swarming.alias.apply(value, d.key));
23281 });
23282 pMap[d.key] = aliased;
23301 } 23283 }
23302 }); 23284 });
23303 23285
23304 // Add some options that might not show up. 23286 // Add some options that might not show up.
23305 pMap["android_devices"].push("0"); 23287 pMap["android_devices"].push("0");
23306 pMap["device_os"].push("none"); 23288 pMap["device_os"].push("none");
23307 pMap["device_type"].push("none"); 23289 pMap["device_type"].push("none");
23308 23290
23309 pMap["id"] = []; 23291 pMap["id"] = [];
23310 23292
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after
23981 Fired when the animation finishes. 23963 Fired when the animation finishes.
23982 This is useful if you want to wait until 23964 This is useful if you want to wait until
23983 the ripple animation finishes to perform some action. 23965 the ripple animation finishes to perform some action.
23984 23966
23985 @event transitionend 23967 @event transitionend
23986 Event param: {{node: Object}} detail Contains the animated node. 23968 Event param: {{node: Object}} detail Contains the animated node.
23987 */ 23969 */
23988 }); 23970 });
23989 </script> 23971 </script>
23990 </dom-module> 23972 </dom-module>
23973 <dom-module id="error-toast" assetpath="/res/imp/common/">
23974 <template>
23975 <paper-toast id="toast"></paper-toast>
23976 </template>
23977 </dom-module>
23978
23979 <script>
23980 Polymer({
23981 is: "error-toast",
23982
23983 ready: function() {
23984 document.addEventListener('error-sk', function(e) {
23985 this.$.toast.close();
23986 if (e.detail.message) {
23987 this.$.toast.text = e.detail.message;
23988 var duration = 10000;
23989 // duration = 0 is a valid input for "keep open indefinitely".
23990 if (e.detail.duration !== undefined) {
23991 duration = e.detail.duration;
23992 }
23993 this.$.toast.duration = duration;
23994 this.$.toast.show();
23995 } else {
23996 console.log("Empty message?", e);
23997 }
23998 }.bind(this));
23999 },
24000 });
24001 </script>
23991 <dom-module id="task-filters" assetpath="/res/imp/tasklist/"> 24002 <dom-module id="task-filters" assetpath="/res/imp/tasklist/">
23992 <template> 24003 <template>
23993 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio ning query-column-filter-style"> 24004 <style is="custom-style" include="iron-flex iron-flex-alignment iron-positio ning query-column-filter-style">
23994 .item.wide { 24005 .item.wide {
23995 max-width: 400px; 24006 max-width: 400px;
23996 } 24007 }
23997 .selector.wide { 24008 .selector.wide {
23998 min-width: 275px; 24009 min-width: 275px;
23999 } 24010 }
24000 24011
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
24278 }); 24289 });
24279 }); 24290 });
24280 24291
24281 // Turn the Map<Object,Map<Boolean>> into a Map<Object,Array<String>> 24292 // Turn the Map<Object,Map<Boolean>> into a Map<Object,Array<String>>
24282 // with all of the aliases applied. 24293 // with all of the aliases applied.
24283 var pMap = {}; 24294 var pMap = {};
24284 for (key in map) { 24295 for (key in map) {
24285 var values = Object.keys(map[key]); 24296 var values = Object.keys(map[key]);
24286 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(key) === -1) { 24297 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(key) === -1) {
24287 pMap[key] = values; 24298 pMap[key] = values;
24288 } else if (key === "gpu") {
24289 var gpus = [];
24290 values.forEach(function(g){
24291 var alias = swarming.alias.gpu(g);
24292 if (alias !== "unknown") {
24293 gpus.push(swarming.alias.apply(g, alias));
24294 } else {
24295 gpus.push(g);
24296 }
24297 }.bind(this));
24298 pMap["gpu"] = gpus;
24299 } else if (key === "device_type") {
24300 var devs = [];
24301 values.forEach(function(dt){
24302 var alias = swarming.alias.android(dt);
24303 if (alias !== "unknown") {
24304 devs.push(swarming.alias.apply(dt, alias));
24305 } else {
24306 devs.push(dt);
24307 }
24308 }.bind(this));
24309 pMap["device_type"] = devs;
24310 } else { 24299 } else {
24311 console.log("Unknown alias type: ", d); 24300 var aliased = [];
24301 values.forEach(function(value){
24302 aliased.push(swarming.alias.apply(value, key));
24303 });
24304 pMap[key] = aliased;
24312 } 24305 }
24313 } 24306 }
24314 24307
24315 // Add some options that might not show up. 24308 // Add some options that might not show up.
24316 pMap["android_devices"].push("0"); 24309 pMap["android_devices"].push("0");
24317 pMap["device_os"].push("none"); 24310 pMap["device_os"].push("none");
24318 pMap["device_type"].push("none"); 24311 pMap["device_type"].push("none");
24319 pMap["user"].push("none"); 24312 pMap["user"].push("none");
24320 24313
24321 // Custom filter options 24314 // Custom filter options
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
24417 </url-param> 24410 </url-param>
24418 24411
24419 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Task List"> 24412 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Task List">
24420 24413
24421 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 24414 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
24422 24415
24423 <div hidden$="[[_not(_signed_in)]]"> 24416 <div hidden$="[[_not(_signed_in)]]">
24424 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_ params]]" tasks="{{_items}}" busy="{{_busy}}" primary_map="{{_primary_map}}" pri mary_arr="{{_primary_arr}}"> 24417 <task-list-data auth_headers="[[_auth_headers]]" query_params="[[_query_ params]]" tasks="{{_items}}" busy="{{_busy}}" primary_map="{{_primary_map}}" pri mary_arr="{{_primary_arr}}">
24425 </task-list-data> 24418 </task-list-data>
24426 24419
24427 <paper-toast id="toast"></paper-toast> 24420 <error-toast></error-toast>
24428 24421
24429 <div class="horizontal layout"> 24422 <div class="horizontal layout">
24430 24423
24431 <task-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_a rr]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter} }"> 24424 <task-filters primary_map="[[_primary_map]]" primary_arr="[[_primary_a rr]]" columns="{{_columns}}" query_params="{{_query_params}}" filter="{{_filter} }">
24432 </task-filters> 24425 </task-filters>
24433 24426
24434 </div> 24427 </div>
24435 24428
24436 <table class="task-list"> 24429 <table class="task-list">
24437 <thead on-sort_change="_sortChange"> 24430 <thead on-sort_change="_sortChange">
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
24617 }, 24610 },
24618 24611
24619 _cancelTask: function(e) { 24612 _cancelTask: function(e) {
24620 var task = e.model.task; 24613 var task = e.model.task;
24621 if (!task || !task.task_id) { 24614 if (!task || !task.task_id) {
24622 console.log("Missing task info", task); 24615 console.log("Missing task info", task);
24623 return 24616 return
24624 } 24617 }
24625 var id = task.task_id 24618 var id = task.task_id
24626 24619
24627 // Keep toast displayed until we hear back from the cancel.
24628 this.$.toast.duration = 0;
24629 this.$.toast.text="Canceling task " + id;
24630 this.$.toast.open();
24631 var url = "/_ah/api/swarming/v1/task/" + id +"/cancel"; 24620 var url = "/_ah/api/swarming/v1/task/" + id +"/cancel";
24632 sk.request("POST", url, undefined, this._auth_headers).then(function(res ponse) { 24621 swarming.postWithToast(url, "Canceling task " + id, this._auth_headers);
24633 this.$.toast.close();
24634 this.$.toast.show({
24635 text: "Request sent. Response: "+response,
24636 duration: 3000,
24637 });
24638 }.bind(this)).catch(function(reason) {
24639 console.log("Cancellation failed", reason);
24640 this.$.toast.close();
24641 this.$.toast.show({
24642 text: "Request failed. Reason: "+reason,
24643 duration: 3000,
24644 });
24645 }.bind(this));
24646 }, 24622 },
24647 24623
24648 _tag: function(task, col) { 24624 _tag: function(task, col) {
24649 if (!task || !task.tagMap) { 24625 if (!task || !task.tagMap) {
24650 return undefined; 24626 return undefined;
24651 } 24627 }
24652 return task.tagMap[col]; 24628 return task.tagMap[col];
24653 }, 24629 },
24654 24630
24655 _taskLink: function(taskId) { 24631 _taskLink: function(taskId) {
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
24911 _calcSize: function() { 24887 _calcSize: function() {
24912 return this.getBoundingClientRect()[this.dimension] + 'px'; 24888 return this.getBoundingClientRect()[this.dimension] + 'px';
24913 } 24889 }
24914 24890
24915 }); 24891 });
24916 24892
24917 </script> 24893 </script>
24918 <script> 24894 <script>
24919 24895
24920 /** 24896 /**
24897 * `Polymer.NeonAnimatableBehavior` is implemented by elements containing anim ations for use with
24898 * elements implementing `Polymer.NeonAnimationRunnerBehavior`.
24899 * @polymerBehavior
24900 */
24901 Polymer.NeonAnimatableBehavior = {
24902
24903 properties: {
24904
24905 /**
24906 * Animation configuration. See README for more info.
24907 */
24908 animationConfig: {
24909 type: Object
24910 },
24911
24912 /**
24913 * Convenience property for setting an 'entry' animation. Do not set `anim ationConfig.entry`
24914 * manually if using this. The animated node is set to `this` if using thi s property.
24915 */
24916 entryAnimation: {
24917 observer: '_entryAnimationChanged',
24918 type: String
24919 },
24920
24921 /**
24922 * Convenience property for setting an 'exit' animation. Do not set `anima tionConfig.exit`
24923 * manually if using this. The animated node is set to `this` if using thi s property.
24924 */
24925 exitAnimation: {
24926 observer: '_exitAnimationChanged',
24927 type: String
24928 }
24929
24930 },
24931
24932 _entryAnimationChanged: function() {
24933 this.animationConfig = this.animationConfig || {};
24934 this.animationConfig['entry'] = [{
24935 name: this.entryAnimation,
24936 node: this
24937 }];
24938 },
24939
24940 _exitAnimationChanged: function() {
24941 this.animationConfig = this.animationConfig || {};
24942 this.animationConfig['exit'] = [{
24943 name: this.exitAnimation,
24944 node: this
24945 }];
24946 },
24947
24948 _copyProperties: function(config1, config2) {
24949 // shallowly copy properties from config2 to config1
24950 for (var property in config2) {
24951 config1[property] = config2[property];
24952 }
24953 },
24954
24955 _cloneConfig: function(config) {
24956 var clone = {
24957 isClone: true
24958 };
24959 this._copyProperties(clone, config);
24960 return clone;
24961 },
24962
24963 _getAnimationConfigRecursive: function(type, map, allConfigs) {
24964 if (!this.animationConfig) {
24965 return;
24966 }
24967
24968 if(this.animationConfig.value && typeof this.animationConfig.value === 'fu nction') {
24969 this._warn(this._logf('playAnimation', "Please put 'animationConfig' ins ide of your components 'properties' object instead of outside of it."));
24970 return;
24971 }
24972
24973 // type is optional
24974 var thisConfig;
24975 if (type) {
24976 thisConfig = this.animationConfig[type];
24977 } else {
24978 thisConfig = this.animationConfig;
24979 }
24980
24981 if (!Array.isArray(thisConfig)) {
24982 thisConfig = [thisConfig];
24983 }
24984
24985 // iterate animations and recurse to process configurations from child nod es
24986 if (thisConfig) {
24987 for (var config, index = 0; config = thisConfig[index]; index++) {
24988 if (config.animatable) {
24989 config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
24990 } else {
24991 if (config.id) {
24992 var cachedConfig = map[config.id];
24993 if (cachedConfig) {
24994 // merge configurations with the same id, making a clone lazily
24995 if (!cachedConfig.isClone) {
24996 map[config.id] = this._cloneConfig(cachedConfig)
24997 cachedConfig = map[config.id];
24998 }
24999 this._copyProperties(cachedConfig, config);
25000 } else {
25001 // put any configs with an id into a map
25002 map[config.id] = config;
25003 }
25004 } else {
25005 allConfigs.push(config);
25006 }
25007 }
25008 }
25009 }
25010 },
25011
25012 /**
25013 * An element implementing `Polymer.NeonAnimationRunnerBehavior` calls this method to configure
25014 * an animation with an optional type. Elements implementing `Polymer.NeonAn imatableBehavior`
25015 * should define the property `animationConfig`, which is either a configura tion object
25016 * or a map of animation type to array of configuration objects.
25017 */
25018 getAnimationConfig: function(type) {
25019 var map = {};
25020 var allConfigs = [];
25021 this._getAnimationConfigRecursive(type, map, allConfigs);
25022 // append the configurations saved in the map to the array
25023 for (var key in map) {
25024 allConfigs.push(map[key]);
25025 }
25026 return allConfigs;
25027 }
25028
25029 };
25030
25031 </script>
25032 <script>
25033
25034 /**
25035 * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations.
25036 *
25037 * @polymerBehavior Polymer.NeonAnimationRunnerBehavior
25038 */
25039 Polymer.NeonAnimationRunnerBehaviorImpl = {
25040
25041 _configureAnimations: function(configs) {
25042 var results = [];
25043 if (configs.length > 0) {
25044 for (var config, index = 0; config = configs[index]; index++) {
25045 var neonAnimation = document.createElement(config.name);
25046 // is this element actually a neon animation?
25047 if (neonAnimation.isNeonAnimation) {
25048 var result = null;
25049 // configuration or play could fail if polyfills aren't loaded
25050 try {
25051 result = neonAnimation.configure(config);
25052 // Check if we have an Effect rather than an Animation
25053 if (typeof result.cancel != 'function') {
25054 result = document.timeline.play(result);
25055 }
25056 } catch (e) {
25057 result = null;
25058 console.warn('Couldnt play', '(', config.name, ').', e);
25059 }
25060 if (result) {
25061 results.push({
25062 neonAnimation: neonAnimation,
25063 config: config,
25064 animation: result,
25065 });
25066 }
25067 } else {
25068 console.warn(this.is + ':', config.name, 'not found!');
25069 }
25070 }
25071 }
25072 return results;
25073 },
25074
25075 _shouldComplete: function(activeEntries) {
25076 var finished = true;
25077 for (var i = 0; i < activeEntries.length; i++) {
25078 if (activeEntries[i].animation.playState != 'finished') {
25079 finished = false;
25080 break;
25081 }
25082 }
25083 return finished;
25084 },
25085
25086 _complete: function(activeEntries) {
25087 for (var i = 0; i < activeEntries.length; i++) {
25088 activeEntries[i].neonAnimation.complete(activeEntries[i].config);
25089 }
25090 for (var i = 0; i < activeEntries.length; i++) {
25091 activeEntries[i].animation.cancel();
25092 }
25093 },
25094
25095 /**
25096 * Plays an animation with an optional `type`.
25097 * @param {string=} type
25098 * @param {!Object=} cookie
25099 */
25100 playAnimation: function(type, cookie) {
25101 var configs = this.getAnimationConfig(type);
25102 if (!configs) {
25103 return;
25104 }
25105 this._active = this._active || {};
25106 if (this._active[type]) {
25107 this._complete(this._active[type]);
25108 delete this._active[type];
25109 }
25110
25111 var activeEntries = this._configureAnimations(configs);
25112
25113 if (activeEntries.length == 0) {
25114 this.fire('neon-animation-finish', cookie, {bubbles: false});
25115 return;
25116 }
25117
25118 this._active[type] = activeEntries;
25119
25120 for (var i = 0; i < activeEntries.length; i++) {
25121 activeEntries[i].animation.onfinish = function() {
25122 if (this._shouldComplete(activeEntries)) {
25123 this._complete(activeEntries);
25124 delete this._active[type];
25125 this.fire('neon-animation-finish', cookie, {bubbles: false});
25126 }
25127 }.bind(this);
25128 }
25129 },
25130
25131 /**
25132 * Cancels the currently running animations.
25133 */
25134 cancelAnimation: function() {
25135 for (var k in this._animations) {
25136 this._animations[k].cancel();
25137 }
25138 this._animations = {};
25139 }
25140 };
25141
25142 /** @polymerBehavior Polymer.NeonAnimationRunnerBehavior */
25143 Polymer.NeonAnimationRunnerBehavior = [
25144 Polymer.NeonAnimatableBehavior,
25145 Polymer.NeonAnimationRunnerBehaviorImpl
25146 ];
25147 </script>
25148 <script>
25149
25150 /**
25151 Use `Polymer.PaperDialogBehavior` and `paper-dialog-shared-styles.html` to imple ment a Material Design
25152 dialog.
25153
25154 For example, if `<paper-dialog-impl>` implements this behavior:
25155
25156 <paper-dialog-impl>
25157 <h2>Header</h2>
25158 <div>Dialog body</div>
25159 <div class="buttons">
25160 <paper-button dialog-dismiss>Cancel</paper-button>
25161 <paper-button dialog-confirm>Accept</paper-button>
25162 </div>
25163 </paper-dialog-impl>
25164
25165 `paper-dialog-shared-styles.html` provide styles for a header, content area, and an action area for buttons.
25166 Use the `<h2>` tag for the header and the `buttons` class for the action area. Y ou can use the
25167 `paper-dialog-scrollable` element (in its own repository) if you need a scrollin g content area.
25168
25169 Use the `dialog-dismiss` and `dialog-confirm` attributes on interactive controls to close the
25170 dialog. If the user dismisses the dialog with `dialog-confirm`, the `closingReas on` will update
25171 to include `confirmed: true`.
25172
25173 ### Accessibility
25174
25175 This element has `role="dialog"` by default. Depending on the context, it may be more appropriate
25176 to override this attribute with `role="alertdialog"`.
25177
25178 If `modal` is set, the element will prevent the focus from exiting the element.
25179 It will also ensure that focus remains in the dialog.
25180
25181 @hero hero.svg
25182 @demo demo/index.html
25183 @polymerBehavior Polymer.PaperDialogBehavior
25184 */
25185
25186 Polymer.PaperDialogBehaviorImpl = {
25187
25188 hostAttributes: {
25189 'role': 'dialog',
25190 'tabindex': '-1'
25191 },
25192
25193 properties: {
25194
25195 /**
25196 * If `modal` is true, this implies `no-cancel-on-outside-click`, `no-canc el-on-esc-key` and `with-backdrop`.
25197 */
25198 modal: {
25199 type: Boolean,
25200 value: false
25201 }
25202
25203 },
25204
25205 observers: [
25206 '_modalChanged(modal, _readied)'
25207 ],
25208
25209 listeners: {
25210 'tap': '_onDialogClick'
25211 },
25212
25213 ready: function () {
25214 // Only now these properties can be read.
25215 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
25216 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
25217 this.__prevWithBackdrop = this.withBackdrop;
25218 },
25219
25220 _modalChanged: function(modal, readied) {
25221 // modal implies noCancelOnOutsideClick, noCancelOnEscKey and withBackdrop .
25222 // We need to wait for the element to be ready before we can read the
25223 // properties values.
25224 if (!readied) {
25225 return;
25226 }
25227
25228 if (modal) {
25229 this.__prevNoCancelOnOutsideClick = this.noCancelOnOutsideClick;
25230 this.__prevNoCancelOnEscKey = this.noCancelOnEscKey;
25231 this.__prevWithBackdrop = this.withBackdrop;
25232 this.noCancelOnOutsideClick = true;
25233 this.noCancelOnEscKey = true;
25234 this.withBackdrop = true;
25235 } else {
25236 // If the value was changed to false, let it false.
25237 this.noCancelOnOutsideClick = this.noCancelOnOutsideClick &&
25238 this.__prevNoCancelOnOutsideClick;
25239 this.noCancelOnEscKey = this.noCancelOnEscKey &&
25240 this.__prevNoCancelOnEscKey;
25241 this.withBackdrop = this.withBackdrop && this.__prevWithBackdrop;
25242 }
25243 },
25244
25245 _updateClosingReasonConfirmed: function(confirmed) {
25246 this.closingReason = this.closingReason || {};
25247 this.closingReason.confirmed = confirmed;
25248 },
25249
25250 /**
25251 * Will dismiss the dialog if user clicked on an element with dialog-dismiss
25252 * or dialog-confirm attribute.
25253 */
25254 _onDialogClick: function(event) {
25255 // Search for the element with dialog-confirm or dialog-dismiss,
25256 // from the root target until this (excluded).
25257 var path = Polymer.dom(event).path;
25258 for (var i = 0; i < path.indexOf(this); i++) {
25259 var target = path[i];
25260 if (target.hasAttribute && (target.hasAttribute('dialog-dismiss') || tar get.hasAttribute('dialog-confirm'))) {
25261 this._updateClosingReasonConfirmed(target.hasAttribute('dialog-confirm '));
25262 this.close();
25263 event.stopPropagation();
25264 break;
25265 }
25266 }
25267 }
25268
25269 };
25270
25271 /** @polymerBehavior */
25272 Polymer.PaperDialogBehavior = [Polymer.IronOverlayBehavior, Polymer.PaperDialo gBehaviorImpl];
25273
25274 </script>
25275
25276
25277 <dom-module id="paper-dialog-shared-styles" assetpath="/res/imp/bower_components /paper-dialog-behavior/">
25278 <template>
25279 <style>
25280 :host {
25281 display: block;
25282 margin: 24px 40px;
25283
25284 background: var(--paper-dialog-background-color, --primary-background-co lor);
25285 color: var(--paper-dialog-color, --primary-text-color);
25286
25287 @apply(--paper-font-body1);
25288 @apply(--shadow-elevation-16dp);
25289 @apply(--paper-dialog);
25290 }
25291
25292 :host > ::content > * {
25293 margin-top: 20px;
25294 padding: 0 24px;
25295 }
25296
25297 :host > ::content > .no-padding {
25298 padding: 0;
25299 }
25300
25301 :host > ::content > *:first-child {
25302 margin-top: 24px;
25303 }
25304
25305 :host > ::content > *:last-child {
25306 margin-bottom: 24px;
25307 }
25308
25309 :host > ::content h2 {
25310 position: relative;
25311 margin: 0;
25312 @apply(--paper-font-title);
25313
25314 @apply(--paper-dialog-title);
25315 }
25316
25317 :host > ::content .buttons {
25318 position: relative;
25319 padding: 8px 8px 8px 24px;
25320 margin: 0;
25321
25322 color: var(--paper-dialog-button-color, --primary-color);
25323
25324 @apply(--layout-horizontal);
25325 @apply(--layout-end-justified);
25326 }
25327 </style>
25328 </template>
25329 </dom-module>
25330
25331
25332 <dom-module id="paper-dialog" assetpath="/res/imp/bower_components/paper-dialog/ ">
25333 <template>
25334 <style include="paper-dialog-shared-styles"></style>
25335 <content></content>
25336 </template>
25337 </dom-module>
25338
25339 <script>
25340
25341 (function() {
25342
25343 Polymer({
25344
25345 is: 'paper-dialog',
25346
25347 behaviors: [
25348 Polymer.PaperDialogBehavior,
25349 Polymer.NeonAnimationRunnerBehavior
25350 ],
25351
25352 listeners: {
25353 'neon-animation-finish': '_onNeonAnimationFinish'
25354 },
25355
25356 _renderOpened: function() {
25357 this.cancelAnimation();
25358 this.playAnimation('entry');
25359 },
25360
25361 _renderClosed: function() {
25362 this.cancelAnimation();
25363 this.playAnimation('exit');
25364 },
25365
25366 _onNeonAnimationFinish: function() {
25367 if (this.opened) {
25368 this._finishRenderOpened();
25369 } else {
25370 this._finishRenderClosed();
25371 }
25372 }
25373
25374 });
25375
25376 })();
25377
25378 </script>
25379 <script>
25380
25381 /**
24921 * `Polymer.IronMenuBehavior` implements accessible menu behavior. 25382 * `Polymer.IronMenuBehavior` implements accessible menu behavior.
24922 * 25383 *
24923 * @demo demo/index.html 25384 * @demo demo/index.html
24924 * @polymerBehavior Polymer.IronMenuBehavior 25385 * @polymerBehavior Polymer.IronMenuBehavior
24925 */ 25386 */
24926 Polymer.IronMenuBehaviorImpl = { 25387 Polymer.IronMenuBehaviorImpl = {
24927 25388
24928 properties: { 25389 properties: {
24929 25390
24930 /** 25391 /**
(...skipping 1241 matching lines...) Expand 10 before | Expand all | Expand 10 after
26172 bot.disks = []; 26633 bot.disks = [];
26173 for (var i = 0; i < keys.length; i++) { 26634 for (var i = 0; i < keys.length; i++) {
26174 bot.disks.push({"id":keys[i], "mb":disks[keys[i]].free_mb}); 26635 bot.disks.push({"id":keys[i], "mb":disks[keys[i]].free_mb});
26175 } 26636 }
26176 // Sort these so the biggest disk comes first. 26637 // Sort these so the biggest disk comes first.
26177 bot.disks.sort(function(a, b) { 26638 bot.disks.sort(function(a, b) {
26178 return b.mb - a.mb; 26639 return b.mb - a.mb;
26179 }); 26640 });
26180 } 26641 }
26181 26642
26643 bot.dimensions = bot.dimensions || [];
26644 bot.dimensions.forEach(function(dim) {
26645 if (swarming.alias.DIMENSIONS_WITH_ALIASES.indexOf(dim.key) !== -1) {
26646 dim.value.forEach(function(value, i){
26647 dim.value[i] = swarming.alias.apply(value, dim.key);
26648 });
26649 }
26650 });
26651
26182 BOT_TIMES.forEach(function(time) { 26652 BOT_TIMES.forEach(function(time) {
26183 if (bot[time]) { 26653 if (bot[time]) {
26184 bot[time] = new Date(bot[time]); 26654 bot[time] = new Date(bot[time]);
26185 bot["human_"+time] = formatDate(bot[time]); 26655 bot["human_"+time] = formatDate(bot[time]);
26186 } 26656 }
26187 }); 26657 });
26188 return bot; 26658 return bot;
26189 }, 26659 },
26190 26660
26191 _parseEvents: function(events) { 26661 _parseEvents: function(events) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
26277 max-height: 50px; 26747 max-height: 50px;
26278 width: initial; 26748 width: initial;
26279 height: initial; 26749 height: initial;
26280 } 26750 }
26281 26751
26282 table { 26752 table {
26283 border-collapse: collapse; 26753 border-collapse: collapse;
26284 margin-left: 5px; 26754 margin-left: 5px;
26285 margin-bottom: 5px; 26755 margin-bottom: 5px;
26286 } 26756 }
26287 td, th { 26757 td,
26758 th {
26288 border: 1px solid #BBB; 26759 border: 1px solid #BBB;
26289 padding: 5px; 26760 padding: 5px;
26290 } 26761 }
26291 26762
26292 .quarantined, .failed_task { 26763 .quarantined,
26764 .failed_task {
26293 background-color: #ffdddd; 26765 background-color: #ffdddd;
26294 } 26766 }
26295 .dead { 26767 .dead,
26768 .bot_died {
26296 background-color: #cccccc; 26769 background-color: #cccccc;
26297 } 26770 }
26298 26771
26299 .message { 26772 .message {
26300 white-space: pre-line; 26773 white-space: pre-line;
26301 font-family: monospace; 26774 font-family: monospace;
26302 } 26775 }
26303 26776
26304 .bot_state { 26777 .bot_state {
26305 white-space: pre; 26778 white-space: pre;
26306 font-family: monospace; 26779 font-family: monospace;
26307 margin-bottom: 10px; 26780 margin-bottom: 10px;
26308 } 26781 }
26309 26782
26310 .tabs { 26783 .tabs {
26311 background-color: #1F78B4; 26784 background-color: #1F78B4;
26312 color: #fff; 26785 color: #fff;
26313 max-width: 600px; 26786 max-width: 600px;
26314 --paper-checkbox-label-color: #fff; 26787 --paper-checkbox-label-color: #fff;
26315 margin-left: 5px; 26788 margin-left: 5px;
26316 } 26789 }
26317 26790
26318 .tasks_table, .events_table { 26791 .tasks_table,
26792 .events_table {
26319 border: 3px solid #1F78B4; 26793 border: 3px solid #1F78B4;
26320 } 26794 }
26321 26795
26322 paper-checkbox { 26796 paper-checkbox {
26323 --paper-checkbox-label-color: #fff; 26797 --paper-checkbox-label-color: #fff;
26324 --paper-checkbox-checked-color: #fff; 26798 --paper-checkbox-checked-color: #fff;
26325 --paper-checkbox-checkmark-color: #000; 26799 --paper-checkbox-checkmark-color: #000;
26326 --paper-checkbox-unchecked-color: #fff; 26800 --paper-checkbox-unchecked-color: #fff;
26327 padding: 3px; 26801 padding: 3px;
26328 } 26802 }
26329 26803
26330 paper-tab.iron-selected { 26804 paper-tab.iron-selected {
26331 background-color: #A6CEE3; 26805 background-color: #A6CEE3;
26332 border: 3px solid #1F78B4; 26806 border: 3px solid #1F78B4;
26333 color: #000; 26807 color: #000;
26334 font-weight: bold; 26808 font-weight: bold;
26335 text-decoration: underline; 26809 text-decoration: underline;
26336 } 26810 }
26337 26811
26812 paper-dialog {
26813 border-radius: 6px;
26814 }
26815
26338 </style> 26816 </style>
26339 26817
26340 <url-param name="id" value="{{bot_id}}"> 26818 <url-param name="id" value="{{bot_id}}">
26341 </url-param> 26819 </url-param>
26342 <url-param name="show_all_events" value="{{_show_all}}"> 26820 <url-param name="show_all_events" value="{{_show_all}}">
26343 </url-param> 26821 </url-param>
26344 <url-param name="selected" value="{{_selected}}"> 26822 <url-param name="selected" value="{{_selected}}">
26345 </url-param> 26823 </url-param>
26346 <url-param name="show_state" value="{{_show_state}}"> 26824 <url-param name="show_state" value="{{_show_state}}">
26347 </url-param> 26825 </url-param>
26348 26826
26349 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Bot Page"> 26827 <swarming-app client_id="[[client_id]]" auth_headers="{{_auth_headers}}" per missions="{{_permissions}}" signed_in="{{_signed_in}}" busy="[[_busy]]" name="Sw arming Bot Page">
26350 26828
26351 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2> 26829 <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
26352 26830
26353 <div hidden$="[[_not(_signed_in)]]"> 26831 <div hidden$="[[_not(_signed_in)]]">
26354 26832
26355 <bot-page-data auth_headers="[[_auth_headers]]" bot_id="[[bot_id]]" bot= "{{_bot}}" busy="{{_busy}}" events="{{_events}}" tasks="{{_tasks}}"> 26833 <bot-page-data id="data" auth_headers="[[_auth_headers]]" bot_id="[[bot_ id]]" bot="{{_bot}}" busy="{{_busy}}" events="{{_events}}" tasks="{{_tasks}}">
26356 </bot-page-data> 26834 </bot-page-data>
26357 26835
26358 <div class="header horizontal layout"> 26836 <div class="header horizontal layout">
26359 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input> 26837 <paper-input class="id_input" label="Bot id" value="{{bot_id}}"></pape r-input>
26360 <button> 26838 <button on-click="_refresh">
26361 <iron-icon class="refresh" icon="icons:refresh"></iron-icon> 26839 <iron-icon class="refresh" icon="icons:refresh"></iron-icon>
26362 </button> 26840 </button>
26363 </div> 26841 </div>
26364 26842
26365 <div> 26843 <div>
26366 <table> 26844 <table>
26367 <tbody><tr class$="[[_isDead(_bot)]]"> 26845 <tbody><tr class$="[[_isDead(_bot)]]">
26368 <td>Last Seen</td> 26846 <td>Last Seen</td>
26369 <td title="[[_bot.human_last_seen_ts]]"> 26847 <td title="[[_bot.human_last_seen_ts]]">
26370 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td> 26848 [[_timeDiffExact(_bot.last_seen_ts)]] ago</td>
26371 <td> 26849 <td>
26372 26850
26373 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]"> 26851 <template is="dom-if" if="[[_canShutdown(_bot,_permissions)]]">
26374 <button class="raised"> 26852 <button class="raised" on-click="_promptShutdown">
26375 Shut Down Gracefully 26853 Shut Down Gracefully
26376 </button> 26854 </button>
26377 </template> 26855 </template>
26378 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]"> 26856 <template is="dom-if" if="[[_canDelete(_bot,_permissions)]]">
26379 <button class="raised"> 26857 <button class="raised" on-click="_promptDelete">
26380 Delete 26858 Delete
26381 </button> 26859 </button>
26382 </template> 26860 </template>
26383 </td> 26861 </td>
26384 </tr> 26862 </tr>
26385 <template is="dom-if" if="[[_bot.quarantined]]"> 26863 <template is="dom-if" if="[[_bot.quarantined]]">
26386 <tr class="quarantined"> 26864 <tr class="quarantined">
26387 <td>Quarantined</td> 26865 <td>Quarantined</td>
26388 <td colspan="2">[[_quarantineMessage(_bot)]]</td> 26866 <td colspan="2">[[_quarantineMessage(_bot)]]</td>
26389 </tr> 26867 </tr>
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
26472 <thead> 26950 <thead>
26473 <tr> 26951 <tr>
26474 <th>Task</th> 26952 <th>Task</th>
26475 <th>Started</th> 26953 <th>Started</th>
26476 <th>Duration</th> 26954 <th>Duration</th>
26477 <th>Result</th> 26955 <th>Result</th>
26478 </tr> 26956 </tr>
26479 </thead> 26957 </thead>
26480 <tbody> 26958 <tbody>
26481 <template is="dom-repeat" items="{{_tasks}}" as="task"> 26959 <template is="dom-repeat" items="{{_tasks}}" as="task">
26482 <tr> 26960 <tr class$="[[_taskClass(task)]]">
26483 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td> 26961 <td><a target="_blank" href$="[[_taskLink(task.task_id)]]">[[t ask.name]]</a></td>
26484 <td>[[task.human_started_ts]]</td> 26962 <td>[[task.human_started_ts]]</td>
26485 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td> 26963 <td title="[[task.human_completed_ts]]">[[task.human_duration] ]</td>
26486 <td>[[task.state]]</td> 26964 <td>[[task.state]]</td>
26487 </tr> 26965 </tr>
26488 </template> 26966 </template>
26489 </tbody> 26967 </tbody>
26490 </table> 26968 </table>
26491 </template> 26969 </template>
26492 26970
(...skipping 18 matching lines...) Expand all
26511 <td> 26989 <td>
26512 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a> 26990 <a target="_blank" href$="[[_luciLink(_bot.version)]]">[[_sh orten(_bot.version,'8')]]</a>
26513 </td> 26991 </td>
26514 </tr> 26992 </tr>
26515 </template> 26993 </template>
26516 </tbody> 26994 </tbody>
26517 </table> 26995 </table>
26518 </template> 26996 </template>
26519 </div> 26997 </div>
26520 26998
26999 </swarming-app>
26521 27000
26522 </swarming-app> 27001 <paper-dialog id="prompt" modal="" on-iron-overlay-closed="_promptClosed">
27002 <h2>Are you sure?</h2>
27003 <div>Are you sure you want to [[_dialogPrompt]]?</div>
27004 <div class="buttons">
27005 <paper-button dialog-dismiss="" autofocus="">No</paper-button>
27006 <paper-button dialog-confirm="">Yes</paper-button>
27007 </div>
27008 </paper-dialog>
27009
27010 <error-toast></error-toast>
26523 27011
26524 </template> 27012 </template>
26525 <script> 27013 <script>
26526 (function(){ 27014 (function(){
26527 27015
26528 27016
26529 Polymer({ 27017 Polymer({
26530 is: 'bot-page', 27018 is: 'bot-page',
26531 27019
26532 behaviors: [ 27020 behaviors: [
26533 SwarmingBehaviors.BotPageBehavior, 27021 SwarmingBehaviors.BotPageBehavior,
26534 ], 27022 ],
26535 27023
26536 properties: { 27024 properties: {
26537 bot_id: { 27025 bot_id: {
26538 type: String, 27026 type: String,
26539 }, 27027 },
26540 client_id: { 27028 client_id: {
26541 type: String, 27029 type: String,
26542 }, 27030 },
26543 27031
27032 _auth_headers: {
27033 type: Object,
27034 },
26544 _bot: { 27035 _bot: {
26545 type: Object, 27036 type: Object,
26546 }, 27037 },
27038 _dialogPrompt: {
27039 type: String,
27040 value: "",
27041 },
26547 _selected: { 27042 _selected: {
26548 type: Number, 27043 type: Number,
26549 }, 27044 },
26550 _show_all: { 27045 _show_all: {
26551 type: Boolean, 27046 type: Boolean,
26552 }, 27047 },
26553 _show_state: { 27048 _show_state: {
26554 type: Boolean, 27049 type: Boolean,
26555 } 27050 }
26556 }, 27051 },
(...skipping 10 matching lines...) Expand all
26567 return bot && !bot.is_dead && permissions.terminate_bot; 27062 return bot && !bot.is_dead && permissions.terminate_bot;
26568 }, 27063 },
26569 27064
26570 _concat: function(arr) { 27065 _concat: function(arr) {
26571 if (!arr) { 27066 if (!arr) {
26572 return ""; 27067 return "";
26573 } 27068 }
26574 return arr.join(" | "); 27069 return arr.join(" | ");
26575 }, 27070 },
26576 27071
27072 _deleteBot: function() {
27073 swarming.postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/delete" ,
27074 "Deleting "+this.bot_id, this._auth_headers);
27075 },
27076
26577 _eventList(events, showAll) { 27077 _eventList(events, showAll) {
26578 if (!events) { 27078 if (!events) {
26579 return []; 27079 return [];
26580 } 27080 }
26581 return events.filter(function(e){ 27081 return events.filter(function(e){
26582 return showAll || e.message; 27082 return showAll || e.message;
26583 }); 27083 });
26584 }, 27084 },
26585 27085
26586 _isDead(bot){ 27086 _isDead(bot){
(...skipping 16 matching lines...) Expand all
26603 return 1; 27103 return 1;
26604 } 27104 }
26605 return 1 + arr.length; 27105 return 1 + arr.length;
26606 }, 27106 },
26607 27107
26608 _prettyPrint: function(obj) { 27108 _prettyPrint: function(obj) {
26609 obj = obj || {}; 27109 obj = obj || {};
26610 return JSON.stringify(obj, null, 2); 27110 return JSON.stringify(obj, null, 2);
26611 }, 27111 },
26612 27112
27113 _promptClosed: function(e) {
27114 if (e.detail.confirmed) {
27115 if (this._dialogPrompt.startsWith("shut down")) {
27116 this._shutdownBot();
27117 } else {
27118 this._deleteBot();
27119 }
27120 }
27121 },
27122
27123 _promptDelete: function() {
27124 this.set("_dialogPrompt", "delete "+this.bot_id);
27125 this.$.prompt.open();
27126 },
27127
27128 _promptShutdown: function() {
27129 this.set("_dialogPrompt", "shut down "+this.bot_id);
27130 this.$.prompt.open();
27131 },
27132
26613 _quarantineMessage: function(bot) { 27133 _quarantineMessage: function(bot) {
26614 if (bot && bot.quarantined) { 27134 if (bot && bot.quarantined) {
26615 var msg = bot.state.quarantined; 27135 var msg = bot.state.quarantined;
26616 // Sometimes, the quarantined message is actually in "error". This 27136 // Sometimes, the quarantined message is actually in "error". This
26617 // happens when the bot code has thrown an exception. 27137 // happens when the bot code has thrown an exception.
26618 if (msg === undefined || msg === "true" || msg === true) { 27138 if (msg === undefined || msg === "true" || msg === true) {
26619 msg = this._attribute(bot, "error"); 27139 msg = this._attribute(bot, "error");
26620 } 27140 }
26621 return msg || "True"; 27141 return msg || "True";
26622 } 27142 }
26623 return ""; 27143 return "";
26624 }, 27144 },
26625 27145
27146 _refresh: function() {
27147 this.$.data.request();
27148 },
27149
26626 _shorten: function(str, length) { 27150 _shorten: function(str, length) {
26627 if (!str || ! length) { 27151 if (!str || ! length) {
26628 return ""; 27152 return "";
26629 } 27153 }
26630 return str.substring(0, length); 27154 return str.substring(0, length);
26631 }, 27155 },
26632 27156
27157 _shutdownBot: function() {
27158 swarming.postWithToast("/_ah/api/swarming/v1/bot/"+this.bot_id+"/termina te",
27159 "Shutting down "+this.bot_id, this._auth_headers);
27160 },
27161
26633 _task: function(bot) { 27162 _task: function(bot) {
26634 return (bot && bot.task_id) || "idle"; 27163 return (bot && bot.task_id) || "idle";
26635 }, 27164 },
26636 27165
27166 _taskClass: function(task) {
27167 if (task && task.internal_failure) {
27168 return "bot_died";
27169 }
27170 if (task && task.failure) {
27171 return "failed_task";
27172 }
27173 return "";
27174 },
27175
26637 _taskLink: function(task_id) { 27176 _taskLink: function(task_id) {
26638 // TODO(kjlubick): Migrate this to /newui/ when ready 27177 // TODO(kjlubick): Migrate this to /newui/ when ready
26639 if (task_id) { 27178 if (task_id) {
26640 return "/user/task/" + task_id; 27179 return "/user/task/" + task_id;
26641 } 27180 }
26642 return undefined; 27181 return undefined;
26643 }, 27182 },
26644 27183
26645 _toggleState: function() { 27184 _toggleState: function() {
26646 this.set("_show_state", !this._show_state); 27185 this.set("_show_state", !this._show_state);
26647 } 27186 }
26648 27187
26649 }); 27188 });
26650 })(); 27189 })();
26651 </script> 27190 </script>
26652 </dom-module></div></body></html> 27191 </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