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

Side by Side Diff: appengine/swarming/elements/res/imp/botpage/bot-page-summary.html

Issue 2408743002: Move elements/ to ui/ (Closed)
Patch Set: rebase again Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 This in an HTML Import-able file that contains the definition
3 of the following elements:
4
5 <bot-page-summary>
6
7 Usage:
8
9 <bot-page-summary></bot-page-summary>
10
11 Properties:
12 None.
13
14 Methods:
15 None.
16
17 Events:
18 None.
19 -->
20 <link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox .html">
21
22 <link rel="import" href="/res/imp/common/single-page-style.html">
23 <link rel="import" href="/res/imp/common/sort-toggle.html">
24 <link rel="import" href="/res/imp/common/url-param.html">
25
26 <link rel="import" href="bot-page-shared-behavior.html">
27
28 <dom-module id="bot-page-summary">
29 <template>
30 <style include="single-page-style">
31 .wrapper {
32 display: table;
33 margin-left: auto;
34 margin-bottom: 10px;
35 margin-right: 5px;
36 }
37
38 paper-checkbox {
39 margin-left: 5px;
40 }
41
42 .thick {
43 border-top-style: solid;
44 }
45 </style>
46
47 <url-param name="show_full_names"
48 value="{{_show_full_names}}">
49 </url-param>
50 <url-param name="show_all_tasks"
51 value="{{_show_all_tasks}}">
52 </url-param>
53 <url-param name="sort_stats"
54 value="{{_sortstr}}"
55 default_value="total:desc">
56 </url-param>
57
58 <div class="wrapper">
59 <table>
60 <thead on-sort_change="_sortChange">
61 <tr>
62 <th>
63 <span>Name</span>
64 <sort-toggle
65 name="full_name"
66 current="[[_sort]]">
67 </sort-toggle>
68 </th>
69 <th>
70 <span>Total</span>
71 <sort-toggle
72 name="total"
73 current="[[_sort]]">
74 </sort-toggle>
75 </th>
76 <th>
77 <span>Success</span>
78 <sort-toggle
79 name="success"
80 current="[[_sort]]">
81 </sort-toggle>
82 </th>
83 <th>
84 <span>Failed</span>
85 <sort-toggle
86 name="failed"
87 current="[[_sort]]">
88 </sort-toggle>
89 </th>
90 <th>
91 <span>Died</span>
92 <sort-toggle
93 name="bot_died"
94 current="[[_sort]]">
95 </sort-toggle>
96 </th>
97 <th>
98 <span>Average Duration</span>
99 <sort-toggle
100 name="avg_duration"
101 current="[[_sort]]">
102 </sort-toggle>
103 </th>
104 <th>
105 <span>Total Duration</span>
106 <sort-toggle
107 name="total_time"
108 current="[[_sort]]">
109 </sort-toggle>
110 </th>
111 <th>Percent of Total</th>
112 </tr>
113 </thead>
114 <tbody>
115 <template is="dom-repeat" items="[[_tasksToShow]]" as="task">
116 <tr>
117 <td hidden$="[[_truthy(_show_full_names)]]" title="[[task.full_nam e]]">[[task.name]]</td>
118 <td hidden$="[[_not(_show_full_names)]]" title="[[task.full_name]] ">[[task.full_name]]</td>
119 <td>[[task.total]]</td>
120 <td>[[task.success]]</td>
121 <td>[[task.failed]]</td>
122 <td>[[task.bot_died]]</td>
123 <td>[[_humanDuration(task.avg_duration)]]</td>
124 <td>[[_humanDuration(task.total_time)]]</td>
125 <td>[[task.total_time_percent]]%</td>
126 </tr>
127 </template>
128 </tbody>
129 <tr class="thick">
130 <td>Total</td>
131 <td>[[_totalStats.total]]</td>
132 <td>[[_totalStats.success]]</td>
133 <td>[[_totalStats.failed]]</td>
134 <td>[[_totalStats.bot_died]]</td>
135 <td>[[_humanDuration(_totalStats.avg_duration)]]</td>
136 <td>[[_humanDuration(_totalStats.total_time)]]</td>
137 <td>100.0%</td>
138 </tr>
139 </table>
140
141 <div>
142 <table>
143 <thead>
144 <tr>
145 <th title="How much time passed between the oldest task fetched an d now.">
146 Total Wall Time
147 </th>
148 <th title="How much of the wall time this bot was busy with a task .">
149 Wall Time Utilization
150 </th>
151 </tr>
152 </thead>
153 <tbody>
154 <tr>
155 <td>[[_humanDuration(_totalStats.wall_time)]]</td>
156 <td>[[_totalStats.wall_time_utilization]]%</td>
157 </tr>
158 </tbody>
159 </table>
160
161 <paper-checkbox
162 checked="{{_show_full_names}}">
163 Show Full Names
164 </paper-checkbox>
165 <paper-checkbox
166 hidden$="[[_cannotExpand]]"
167 checked="{{_show_all_tasks}}">
168 Show All Tasks
169 </paper-checkbox>
170 </div>
171 </div>
172
173 </template>
174 <script>
175 (function(){
176 var SHOW_LIMIT = 15;
177 Polymer({
178 is: 'bot-page-summary',
179
180 behaviors: [
181 SwarmingBehaviors.BotPageBehavior,
182 ],
183
184 properties: {
185 // input
186 tasks: {
187 type: Array,
188 },
189
190 _cannotExpand: {
191 type: Boolean,
192 computed: "_countTasks(_taskStats.*)"
193 },
194 _show_all_tasks: {
195 type: Boolean
196 },
197 _show_full_names: {
198 type: Boolean
199 },
200 _sortstr: {
201 type: String
202 },
203 _sort: {
204 type: Object,
205 computed: "_makeSortObject(_sortstr)",
206 },
207 // _taskStats in an Array<Object> where each object represents one
208 // type of task (e.g. test_windows_release) and aggregate stats
209 // about it (e.g. average duration)
210 _taskStats: {
211 type: Array
212 },
213 // _tasksToShow is a sorted subset of _taskStats. This allows us to
214 // hide some of the tasks (if there are many)
215 _tasksToShow: {
216 type: Array,
217 computed: "_sortAndLimitTasks(_taskStats.*,_sort.*,_show_all_tasks)"
218 },
219 // _totalStats contains the aggregate stats for all tasks.
220 _totalStats: {
221 type: Object
222 }
223 },
224
225 // We define this down here to listen to all array events (e.g. splices)
226 // otherwise we don't update when more tasks are added.
227 observers: ["_aggregate(tasks.*)"],
228
229 _aggregate: function() {
230 if (!this.tasks || !this.tasks.length) {
231 return;
232 }
233 // TODO(kjlubick): Fix sk.now() to be less awkward to use.
234 var now = new Date(sk.now() * 1000);
235 var taskNames = [];
236 var taskAgg = {};
237 var totalStats = {
238 total: this.tasks.length,
239 success: 0,
240 failed: 0,
241 bot_died: 0,
242 avg_duration: 0,
243 total_time: 0,
244 // to compute wall_time, we find the latest task (and assume tasks
245 // come to us chronologically) and find the difference between then
246 // and now.
247 wall_time: (now - this.tasks[this.tasks.length - 1].started_ts) / 1000 ,
248 };
249 this.tasks.forEach(function(t) {
250 var n = t.name.trim();
251 var pieces = n.split('/');
252 if (pieces.length === 5) {
253 // this appears to be a buildbot name
254 // piece 0 is tag "name", piece 3 is "buildername"
255 // We throw the rest away (OS, commit hash, build number) so we
256 // can identify the "true name".
257 n = pieces[0] + "/" + pieces[3];
258 }
259
260 if (!taskAgg[n]) {
261 taskAgg[n] = {
262 full_name: n,
263 name: n,
264 total: 0,
265 success: 0,
266 failed: 0,
267 bot_died: 0,
268 avg_duration: 0,
269 total_time: 0,
270 }
271 }
272
273 taskAgg[n].total++;
274 if (t.failure) {
275 totalStats.failed++;
276 taskAgg[n].failed++;
277 } else if (t.internal_failure) {
278 totalStats.bot_died++;
279 taskAgg[n].bot_died++;
280 } else {
281 totalStats.success++;
282 taskAgg[n].success++;
283 }
284 totalStats.total_time += t.duration;
285 taskAgg[n].total_time += t.duration;
286 });
287
288 totalStats.avg_duration = totalStats.total_time / totalStats.total;
289 totalStats.wall_time_utilization = (totalStats.total_time * 100 / totalS tats.wall_time).toFixed(1);
290 this.set("_totalStats", totalStats);
291
292 // Turn the map into the array and compute total time percent.
293 var names = Object.keys(taskAgg);
294 var taskStats = [];
295 names.forEach(function(n) {
296 taskAgg[n].avg_duration = taskAgg[n].total_time / taskAgg[n].total;
297 taskAgg[n].total_time_percent = (taskAgg[n].total_time * 100 /totalSta ts.total_time).toFixed(1);
298 taskStats.push(taskAgg[n]);
299 });
300
301 // Shorten names if possible by finding the longest common substring
302 // of at least n-1 of the tasks. These parameters can be tweaked; see
303 // https://www.npmjs.com/package/common-substrings for documentation
304 // n-1 seems to be good to avoid not finding decent matches if there
305 // is an oddball task.
306 var substrings = new Substrings({
307 minOccurrence: Math.max(2, names.length-1),
308 minLength: 6,
309 });
310 substrings.build(names);
311 var result = substrings.weighByAverage() || [];
312 // result is an Array<{name:String, source:Array<int>} where the
313 // ints in source are the indices of names that have the substring.
314 // result is sorted with the "best" results first.
315 if (result.length) {
316 result[0].source.forEach(function(idx){
317 var name = taskStats[idx].full_name;
318 taskStats[idx].name = name.replace(result[0].name, "...");
319 });
320 }
321
322 this.set("_taskStats", taskStats);
323 },
324
325 _compare: function(a,b) {
326 if (!this._sort) {
327 return 0;
328 }
329 var dir = 1;
330 if (this._sort.direction === "desc") {
331 dir = -1;
332 }
333 return dir * swarming.naturalCompare(a[this._sort.name], b[this._sort.na me]);
334 },
335
336 _countTasks: function(){
337 return this._taskStats.length <= SHOW_LIMIT;
338 },
339
340 _makeSortObject: function(sortstr){
341 if (!sortstr) {
342 return undefined;
343 }
344 var pieces = sortstr.split(":");
345 if (pieces.length != 2) {
346 // fail safe
347 return {name: "full_name", direction: "asc"};
348 }
349 return {
350 name: pieces[0],
351 direction: pieces[1],
352 }
353 },
354
355 _sortAndLimitTasks: function() {
356 swarming.stableSort(this._taskStats, this._compare.bind(this));
357 var limit = this._taskStats.length;
358 if (!this._show_all_tasks && this._taskStats.length > SHOW_LIMIT) {
359 limit = SHOW_LIMIT;
360 }
361 return this._taskStats.slice(0, limit);
362 },
363
364 _sortChange: function(e) {
365 // The event we get from sort-toggle tells us the name of what needs
366 // to be sorting and how to sort it.
367 if (!(e && e.detail && e.detail.name)) {
368 return;
369 }
370 e.preventDefault();
371 e.stopPropagation();
372 this.set("_sortstr", e.detail.name + ":" + e.detail.direction);
373 },
374
375 });
376 })();
377 </script>
378 </dom-module>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698