| OLD | NEW |
| (Empty) |
| 1 <!-- Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
| 2 Use of this source code is governed by a BSD-style license that can be | |
| 3 found in the LICENSE file. --> | |
| 4 | |
| 5 <link rel="import" href="../bower_components/core-ajax/core-ajax.html"> | |
| 6 | |
| 7 <polymer-element name="build-table" attributes="builds auto"> | |
| 8 <template> | |
| 9 <style> | |
| 10 :host { | |
| 11 font-family: 'RobotoDraft'; | |
| 12 font-size: 13px; | |
| 13 font-weight: 400; | |
| 14 line-height: 1.5; | |
| 15 color: #212121; | |
| 16 } | |
| 17 table { | |
| 18 border-spacing: 0; | |
| 19 } | |
| 20 th, td { | |
| 21 padding: 4px 16px 4px 4px; | |
| 22 text-align: left; | |
| 23 cursor: pointer; | |
| 24 } | |
| 25 .error { | |
| 26 color: red; | |
| 27 font-weight: bold; | |
| 28 } | |
| 29 .warning { | |
| 30 color: orange; | |
| 31 font-weight: bold; | |
| 32 } | |
| 33 .ok { | |
| 34 color: green; | |
| 35 font-weight: bold; | |
| 36 } | |
| 37 tr:hover { | |
| 38 background-color: #e9eaed; | |
| 39 } | |
| 40 th { | |
| 41 background-color: white; | |
| 42 } | |
| 43 th[data-sortdown] { | |
| 44 background-image: url('/images/sort-down.gif'); | |
| 45 background-repeat: no-repeat; | |
| 46 background-position: 95% 40%; | |
| 47 background-color: white; | |
| 48 } | |
| 49 th[data-sortup] { | |
| 50 background-image: url('/images/sort-up.gif'); | |
| 51 background-repeat: no-repeat; | |
| 52 background-position: 95% 40%; | |
| 53 background-color: white; | |
| 54 } | |
| 55 </style> | |
| 56 <table> | |
| 57 <tr> | |
| 58 <th data-type="master" on-click="{{ updateSort }}">Master</th> | |
| 59 <th data-type="builder" on-click="{{ updateSort }}">Builder</th> | |
| 60 <th data-type="buildnumber" on-click="{{ updateSort }}">Build Number</th
> | |
| 61 <th data-type="buildtime" on-click="{{ updateSort }}">Build Time (HH:MM:
SS)</th> | |
| 62 <th data-type="result" on-click="{{ updateSort }}">Result</th> | |
| 63 <th data-type="revision" on-click="{{ updateSort }}">Revision</th> | |
| 64 <th data-type="name" on-click="{{ updateSortForResponse }}">Longest Step
</th> | |
| 65 <th data-type="duration" on-click="{{ updateSortForResponse }}">Longest
Step Duration</th> | |
| 66 <th data-type="percent" on-click="{{ updateSortForResponse }}">Longest S
tep %</th> | |
| 67 </tr> | |
| 68 <template repeat="{{ build in builds }}"> | |
| 69 <tr data-master="{{ build.master }}" | |
| 70 data-builder="{{ build.builder }}" | |
| 71 data-buildnumber="{{ build.buildnumber }}" | |
| 72 on-click="{{ trClick }}"> | |
| 73 <td>{{ build.master }}</td> | |
| 74 <td>{{ build.builder }}</td> | |
| 75 <td>{{ build.buildnumber }}</td> | |
| 76 <td class="{{ howBadIsTime(build.buildtime) }}">{{ build.buildtime | p
rettifyBuildTime }}</td> | |
| 77 <td class="{{ howBadIsResult(build.result) }}">{{ build.result | resul
tToString }}</td> | |
| 78 <td>{{ build.revision }}</td> | |
| 79 <td class='longest-step'>{{ build.response.steps.max.name }}</td> | |
| 80 <td class='longest-step-duration {{ howBadIsTime(build.response.steps.
max.duration) }}'> | |
| 81 {{ build.response.steps.max.duration | prettifyBuildTime }}</td> | |
| 82 <td class='longest-step-percent'>{{ build.response.steps.max.percent |
prettifyPercent }}</td> | |
| 83 <core-ajax url='http://build.chromium.org/p/{{ build.master }}/json/bu
ilders/{{ build.builder }}/builds/{{ build.buildnumber }}' | |
| 84 handleAs='json' auto="{{ auto }}" response="{{ build.response }}" on
-core-response="{{ findLongest }}"></core-ajax> | |
| 85 </tr> | |
| 86 </template> | |
| 87 </table> | |
| 88 </template> | |
| 89 <script> | |
| 90 Polymer('build-table', { | |
| 91 auto: true, | |
| 92 trClick: function(event, detail, sender) { | |
| 93 var master = sender.getAttribute('data-master'); | |
| 94 var builder = sender.getAttribute('data-builder'); | |
| 95 var buildnumber = sender.getAttribute('data-buildnumber'); | |
| 96 var url = 'http://build.chromium.org/p/{1}/builders/{2}/builds/{3}'. | |
| 97 assign(master, builder, buildnumber); | |
| 98 window.open(url); | |
| 99 }, | |
| 100 resultToString: function(value) { | |
| 101 return ["success", "warning", "failure", "skipped", "exception", "retry"
][value]; | |
| 102 }, | |
| 103 prettifyBuildTime: function(value) { | |
| 104 var s = Math.round(value); | |
| 105 var m = 0; | |
| 106 var h = 0; | |
| 107 if (s >= 60) { | |
| 108 m = Math.floor(s / 60); | |
| 109 s = s % 60; | |
| 110 if (m >= 60) { | |
| 111 h = Math.floor(m / 60); | |
| 112 m = m % 60; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 return h + ":" + (m > 9 ? m : '0' + m) + ":" + (s > 9 ? s : '0' + s); | |
| 117 }, | |
| 118 prettifyPercent: function(percent) { | |
| 119 return (percent * 100).toFixed(1) + '%'; | |
| 120 }, | |
| 121 howBadIsTime: function(time) { | |
| 122 if (time > 60 * 60) { | |
| 123 return 'error'; | |
| 124 } else if (time > 30 * 60) { | |
| 125 return 'warning'; | |
| 126 } else { | |
| 127 return ''; | |
| 128 } | |
| 129 }, | |
| 130 howBadIsResult: function(result) { | |
| 131 return ['ok', 'warning', 'error', 'warning', 'error', 'warning'][result]
; | |
| 132 }, | |
| 133 _sort: function(sender, extractor) { | |
| 134 var th = sender; | |
| 135 var sortDir = 'down'; | |
| 136 if (th.getAttribute('data-sortdown')) { | |
| 137 sortDir = 'up'; | |
| 138 } | |
| 139 var headers = this.shadowRoot.querySelectorAll('th'); | |
| 140 for (var i = 0; i < headers.length; i++) { | |
| 141 headers[i].removeAttribute('data-sortdown'); | |
| 142 headers[i].removeAttribute('data-sortup'); | |
| 143 } | |
| 144 th.setAttribute('data-sort' + sortDir, true); | |
| 145 this.builds.sort(function(a, b) { | |
| 146 var aVal = extractor(a), bVal = extractor(b); | |
| 147 if (!isNaN(Number(aVal)) && !isNaN(Number(bVal))) { | |
| 148 if (sortDir == 'down') { | |
| 149 return aVal - bVal; | |
| 150 } else { | |
| 151 return bVal - aVal; | |
| 152 } | |
| 153 } else { | |
| 154 if (sortDir == 'down') { | |
| 155 return aVal.localeCompare(bVal); | |
| 156 } else { | |
| 157 return bVal.localeCompare(aVal); | |
| 158 } | |
| 159 } | |
| 160 }); | |
| 161 }, | |
| 162 updateSort: function(event, detail, sender) { | |
| 163 var type = sender.getAttribute('data-type'); | |
| 164 this._sort(sender, function(a) { return a[type] }); | |
| 165 }, | |
| 166 updateSortForResponse: function(event, detail, sender) { | |
| 167 var type = sender.getAttribute('data-type'); | |
| 168 this._sort(sender, function(a) { return a.response.steps.max[type] }); | |
| 169 }, | |
| 170 findLongest: function(event, data) { | |
| 171 var maxDuration = 0; | |
| 172 var maxDurationName = ''; | |
| 173 var buildDuration = 0; | |
| 174 var steps = data.response.steps; | |
| 175 if (steps == null) | |
| 176 steps.max= {name: 'waiting', duration: 0, percent: 0}; | |
| 177 steps.forEach(function(step) { | |
| 178 var name = step.name | |
| 179 if (name == 'steps') { | |
| 180 return; | |
| 181 } | |
| 182 var duration = step.times[1] - step.times[0]; | |
| 183 if (duration > maxDuration) { | |
| 184 maxDuration = duration; | |
| 185 maxDurationName = name; | |
| 186 } | |
| 187 buildDuration += duration; | |
| 188 }); | |
| 189 steps.max = {name: maxDurationName, duration: maxDuration, percent: maxD
uration / buildDuration}; | |
| 190 } | |
| 191 }); | |
| 192 </script> | |
| 193 </polymer-element> | |
| OLD | NEW |