| <!-- The <push-selection-sk> custom element declaration. |
| |
| Presents a dialog of package choices and generates an event when the user has |
| made a selection. It is a custom element used by <push-server-sk>. |
| |
| Attributes: |
| 'choices' |
| The list of packages that are available. |
| 'choice' |
| The selected package. |
| Events: |
| 'change' |
| A 'change' event is generated when the user selects a package to push. |
| The change event has the following attributes: |
| |
| event.detail.name - The full name of the package selected. |
| Methods: |
| toggle() |
| Toggles the visibility of the selection dialog. |
| --> |
| <style type="text/css" media="screen"> |
| html /deep/ .pushSelection { |
| font-family: monospace; |
| padding: 0.5em; |
| cursor: pointer; |
| } |
| html /deep/ .pushSelection:hover { |
| background: #eee; |
| } |
| html /deep/ .built { |
| color: #D95F02; |
| display:inline; |
| } |
| html /deep/ .userid { |
| color: #7570B3; |
| display:inline; |
| } |
| </style> |
| <polymer-element name="push-selection-sk"> |
| <template> |
| <paper-action-dialog id=chooser heading="Choose a release package to push"> |
| <core-selector id=newChoice> |
| <template repeat="{{p in choices}}"> |
| <div class=pushSelection name="{{p.Name}}"> |
| <core-icon icon="{{choice == p.Name ? 'check' : ''}}" title="Currently installed"></core-icon> |
| <a href="https://github.com/google/skia-buildbot/compare/{{p.Hash}}...HEAD">{{p.Hash | short}}</a> |
| <pre class=built> {{p.Built | humanDiffDate }} </pre> |
| <pre class=userid title="{{p.UserID}}"> {{p.UserID | short}} </pre> |
| {{p.Note}} |
| <core-icon icon="{{p.Dirty ? 'warning' : ''}}" title="Uncommited changes when the package was built."></core-icon> |
| </div> |
| </template> |
| </core-selector> |
| <paper-button dismissive>Cancel</paper-button> |
| </paper-action-dialog> |
| </template> |
| <script> |
| (function() { |
| var deltas = [ |
| { units: "w", delta: 7*24*60*60 }, |
| { units: "d", delta: 24*60*60 }, |
| { units: "h", delta: 60*60 }, |
| { units: "m", delta: 60 }, |
| { units: "s", delta: 1 }, |
| ]; |
| |
| Polymer({ |
| publish: { |
| choices: { |
| value: [], |
| reflect: false |
| }, |
| choice: { |
| value: '', |
| reflect: false |
| } |
| }, |
| |
| ready: function() { |
| var that = this; |
| this.$.newChoice.addEventListener('core-activate', function(e) { |
| that.toggle(); |
| var detail = {name: that.$.newChoice.selected}; |
| that.dispatchEvent(new CustomEvent('change', {detail: detail})); |
| }); |
| }, |
| |
| toggle: function() { |
| this.$.chooser.toggle(); |
| }, |
| |
| // short is a utility function used in templates to truncate strings. |
| short: function(s) { |
| return s.slice(0, 8); |
| }, |
| |
| humanDiffDate: function(s) { |
| var diff = (Date.now() - Date.parse(s))/1000; |
| for (var i=0; i<deltas.length; i++) { |
| if (deltas[i].delta < diff) { |
| var s = Math.round(diff/deltas[i].delta)+deltas[i].units; |
| while (s.length < 4) { |
| s = ' ' + s; |
| } |
| return s; |
| } |
| } |
| return diff + "s"; |
| } |
| |
| }); |
| })(); |
| </script> |
| </polymer-element> |
| |
| <!-- The <push-server-sk> custom element declaration. |
| |
| Displays the server configurations, along with the ability to modify application selections. |
| |
| Attributes: |
| servers: Map of server names to the apps and their versions. Such as: |
| |
| [ |
| { |
| Name: 'skia-monitoring', |
| Installed: [ |
| 'pull/pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T02:09:58Z:79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c.deb', |
| 'logserver/', |
| ] |
| }, |
| { |
| Name: 'skia-testing-b', |
| Installed: [] |
| } |
| ] |
| |
| Note that an entry in Installed can either be a full package path, or |
| just a shortened '{appname}/' version which indicates which app is |
| expected but also signals that no specific release package has been |
| chosen or deployed yet. |
| |
| packages: Map of app names to the list of available versions, sorted from newest to oldest. Such as: |
| |
| { |
| 'pull': [ |
| { |
| Name: 'pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T02:09:58Z:79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c.deb', |
| Hash: '79f6b17ea316c5d877f4f1e3fa9c7a4ea950916c', |
| UserID: 'jcgregorio@jcgregorio.cnc.corp.google.com', |
| Built: '2014-12-08T02:09:58Z', |
| Dirty: true, |
| Note: 'some reason for a push' |
| }, |
| { |
| Name: 'pull:jcgregorio@jcgregorio.cnc.corp.google.com:2014-12-08T01:39:47Z:323894732847ace1289a9a90192123213.deb', |
| Hash: '323894732847ace1289a9a90192123213', |
| UserID: 'jcgregorio@jcgregorio.cnc.corp.google.com', |
| Built: '2014-12-08T01:39:47Z', |
| Dirty: false, |
| Note: 'no reason' |
| } |
| ], |
| 'logserver': [ |
| ] |
| } |
| |
| Events: |
| 'change' |
| A 'change' event is generated when the user selects a package to push. |
| The change event has the following attributes: |
| |
| event.detail.server - The name of the server. |
| event.detail.name - The full name of the package to push. |
| |
| Methods: |
| setConfig(servers, packages) |
| |
| Clicking on an app brings up a selection dialog with all available options, |
| the current one already selected. A selection will update and push. |
| --> |
| <polymer-element name="push-server-sk"> |
| <template> |
| <style type="text/css" media="screen"> |
| table { |
| margin-left: 3em; |
| } |
| h2 { |
| color: #33A02C; |
| margin-left: 1em; |
| display: inline; |
| padding-right: 1em; |
| } |
| .appName { |
| padding-right: 2em; |
| } |
| td core-icon { |
| padding-right: 1em; |
| } |
| paper-button { |
| color: #1f78b4; |
| } |
| paper-button:hover { |
| background: #eee; |
| } |
| </style> |
| <template repeat="{{server in servers}}"> |
| <section> |
| <h2>{{server.Name}}</h2> [<a target=_blank href="http://{{ip[server.Name]}}:10114">monit</a>] [<a target=_blank href="http://{{ip[server.Name]}}:10115">logs</a>] |
| <table> |
| <template repeat="{{id in server.Installed}}"> |
| <tr> |
| <td> |
| <paper-button class=application data-server="{{server.Name}}" data-name="{{id}}" data-app="{{id | prefixOf}}"><core-icon icon="create" title="Edit which package is installed."></core-icon></paper-button> |
| </td> |
| <td><span class=appName>{{id | prefixOf}}</span></td> |
| <td><span class=appName><a href="https://github.com/google/skia-buildbot/compare/{{id | fullHash}}...HEAD">{{id | short}}</a></span></td> |
| <td><core-icon icon="{{packageLookup[id].Latest ? '' : 'alarm'}}" title="Out of date."></core-icon></td> |
| <td><core-icon icon="{{packageLookup[id].Dirty ? 'warning' : ''}}" title="Uncommited changes when the package was built."></core-icon></td> |
| </tr> |
| </template> |
| </table> |
| </section> |
| </template> |
| <push-selection-sk id=extChooser></push-selection-sk> |
| </template> |
| <script> |
| Polymer({ |
| publish: { |
| servers: { |
| value: {}, |
| reflect: false |
| }, |
| packages: { |
| value: {}, |
| reflect: false |
| }, |
| ip: { |
| value: {}, |
| reflect: false |
| }, |
| packageLookup: { |
| value: {}, |
| reflect: false |
| }, |
| server: { |
| value: '', |
| reflect: false |
| } |
| }, |
| |
| ready: function() { |
| var that = this; |
| this.addEventListener('click', function(e) { |
| this.server = ''; |
| var id = ''; |
| var app = ''; |
| // Bump up the parent path until we find our containing .application element. |
| for (var i=0; i<e.path.length; i++) { |
| if (e.path[i]["classList"] && e.path[i].classList.contains('application')) { |
| this.server = e.path[i].dataset.server; |
| id = e.path[i].dataset.name; |
| app = e.path[i].dataset.app; |
| break; |
| } |
| } |
| if (app != "") { |
| this.$.extChooser.choices = this.packages[app]; |
| this.$.extChooser.choice = id; |
| this.$.extChooser.toggle(); |
| } |
| }); |
| |
| // When the push-selection-sk dialog notifies us of a selection |
| // we fill in some more details and pass that along as another |
| // CustomEvent. |
| this.$.extChooser.addEventListener('change', function(e) { |
| var detail = { |
| name: e.detail.name, |
| server: that.server |
| }; |
| that.dispatchEvent(new CustomEvent('change', {detail: detail})); |
| }); |
| }, |
| |
| setConfig: function(servers, packages, ip) { |
| this.servers = servers; |
| this.packages = packages; |
| this.ip = ip; |
| for (appName in this.packages) { |
| var that = this; |
| var latest = true; |
| this.packages[appName].forEach(function(details) { |
| that.packageLookup[details.Name] = details; |
| that.packageLookup[details.Name].Latest = latest; |
| latest = false; |
| }); |
| } |
| }, |
| |
| // prefixOf is a helper used in templates that returns all the text |
| // that appears before the first '/'. |
| prefixOf: function(s) { |
| return s.split('/')[0]; |
| }, |
| |
| // fullHash is a utility function used in templates to extract the full git hash |
| // from a package name. |
| fullHash: function(s) { |
| return s.slice(s.length-44, s.length-4) |
| }, |
| |
| // short is a utility function used in templates to truncate strings. |
| short: function(s) { |
| return this.fullHash(s).slice(0, 6); |
| }, |
| |
| |
| }); |
| </script> |
| </polymer-element> |
| |
| |