blob: b8260965c267a36157fe8ba4a2f7a9160ad57457 [file]
<!-- The <test-summary-sk> custom element declaration.
Displays a summary for the given test.
Attributes:
summary - A object that gives a summary of a test. Should look like:
{
"name": "01-original",
"diameter": 123242,
"untriaged": 2,
"num": 2,
"untHashes": ["ababab...", "2b2b2b2...", ...],
}
query - paramset in URL query string format.
include - boolean, include ignores.
head - boolean, only use digests at head.
details - boolean, if true display the details about the untriaged digests.
limit - The maximum number of traces and digests to show when displaying details.
triage - If true display the image, its closest match, and the triage controls.
Events:
Methods:
focusNext() - Move the focus to the next digest. Returns true if focus actually moved.
focusPrev() - Move the focus to the previous digest. Returns true if focus actually moved.
markFocus(status) - Set the triage status of the digest with focus to 'status'.
-->
<polymer-element name="test-summary-sk">
<template>
<style type="text/css" media="screen">
span {
width: 25em;
display: inline-block;
overflow-wrap: break-word;
margin-left: 1em;
}
span.short {
width: 5em;
}
.detail {
margin-left: 3em;
padding: 0.5em;
}
test-summary-details-sk {
box-shadow: 3px 3px 6px 1px rgba(133,133,133,1);
margin-top: 1em;
margin-bottom: 1em;
margin-left: 3em;
padding: 1em;
}
test-summary-details-sk[data-focus] {
box-shadow: 3px 3px 6px 5px #FF7F00;
}
test-summary-details-sk[triage] {
display: none;
}
test-summary-details-sk[triage][data-diff] {
display: block;
}
.only {
margin-left: 3em;
font-weight: bold;
padding: 1em;
}
paper-spinner {
margin-left: 1em;
}
.blameColumn {
width: 20em;
}
</style>
<div vertical layout>
<div horizontal layout>
<span>
<b>
<a href="?query={{query | filterNames}}%26name%3D{{summary.name}}&include={{include}}&head={{head}}&untonly=false&details=true&limit=500&triage=true">
{{summary.name}}
</a>
</b>
</span>
<!-- <span class=short>{{summary.diameter}}</span> -->
<span class=short>
<a href="cmp/{{summary.name}}?topQuery={{query}}&topIncludeIgnores={{include}}&leftQuery={{query}}&leftIncludeIgnores={{include}}&head={{head}}">
<core-icon icon=apps></core-icon>
</a>
</span>
<span class=short>{{summary.pos}}</span>
<span class=short>{{summary.neg}}</span>
<span class=short>{{summary.untriaged}}</span>
<span class=short>{{summary.num}}</span>
<div class="blameColumn" vertical layout>
<template repeat="{{b in summary.blame}}">
<div>{{b.prob | formatPercent }}% - {{b.author}}</div>
</template>
</div>
<span class=short>
<template if="{{!triage}}">
<a href="/legacy/#/triage/{{summary.name}}?head={{head}}">Legacy Triage</a>
</template>
</span>
</div>
<div vertical layout id=details>
<div horizontal layout center>
<counter-sk id="counter"></counter-sk>
<paper-spinner id="spinner"></paper-spinner>
</div>
<template if="{{details}}">
<template repeat="{{d, i in summary.untHashes}}">
<template if="{{i<limit}}">
<test-summary-details-sk test="{{summary.name}}" images="{{!triage || loaded}}" digest="{{d}}" limit="{{limit}}" triage="{{triage}}"></test-summary-details-sk>
</template>
</template>
<template if="{{summary.untHashes.length>limit}}">
<div class=only>Only the first {{limit}} hashes are shown.</only>
</template>
</template>
</div>
</div>
</template>
<script>
Polymer({
publish: {
summary: {
value: {},
reflect: true,
},
query: {
value: "",
reflect: true,
},
include: {
value: false,
reflect: true,
},
head: {
value: true,
reflect: true,
},
limit: {
value: 0,
reflect: true,
},
details: {
value: false,
reflect: true,
},
triage: {
value: false,
reflect: true,
},
},
created: function() {
this.summary = {};
},
ready: function() {
this.loadedCount = 0;
this.loaded = false;
var that = this;
// Listen for each test-summary-details-sk to complete loading.
this.$.details.addEventListener('details-loaded', function(e) {
// Move the newly loaded element to the right location in the list.
var node = e.detail;
var last = null;
var diffValue = +node.dataset.diff;
// Find the sibling element we should appear before, which is the
// first element with a smaller diff value.
$$('test-summary-details-sk', that.$.details).forEach(function(ele) {
var d = ele.dataset.diff;
if (d) {
if (last == undefined && +d < diffValue) {
last = ele;
}
}
});
// Insert the node, in the list, or as the first child if last=null.
that.$.details.insertBefore(node, last);
// Keep the spinner spinning until all details elements have been loaded.
that.loadedCount++;
that.$.counter.current = that.loadedCount;
if (that.loadedCount == that.summary.untHashes.length) {
that.$.spinner.active = false;
that.$.counter.active = false;
that.loaded = true;
}
});
},
// findFocus returns the current details element with the keyboard focus.
findFocus: function() {
return $$$('test-summary-details-sk[data-focus]', this.shadowRoot)
},
// moveFocus does the actual work of changing the focus from lastEle
// to nextEle.
//
// Returns true if focus actually moved.
moveFocus: function(lastEle, nextEle) {
// Don't wrap around past the bottom of the list.
if (lastEle != null && nextEle == null) {
return false;
}
if (lastEle != null) {
lastEle.removeAttribute('data-focus');
}
// If nothing is selected, then focus on the first details element.
if (nextEle == null) {
nextEle = $$$('test-summary-details-sk', this.shadowRoot);
}
nextEle.setAttribute('data-focus', 'true');
nextEle.scrollIntoView(false);
return true;
},
// Move the focus to the next digest.
focusNext: function() {
var nextEle = null;
var lastEle = this.findFocus();
if (lastEle != null) {
nextEle = lastEle.nextElementSibling;
}
return this.moveFocus(lastEle, nextEle);
},
// Move the focus to the previous digest.
focusPrev: function() {
var nextEle = null;
var lastEle = this.findFocus();
if (lastEle != null) {
nextEle = lastEle.previousElementSibling;
if (nextEle.nodeName == "TEMPLATE") {
nextEle = null;
}
}
return this.moveFocus(lastEle, nextEle);
},
// Set the triage status of the digest with focus to 'status'.
markFocus: function(status) {
if (!this.triage) {
return
}
var focus = this.findFocus();
if (focus != null) {
focus.triggerTriage(status);
}
},
summaryChanged: function() {
this.dataset.name = this.summary.name;
this.dataset.diameter = this.summary.diameter;
this.dataset.pos = this.summary.pos;
this.dataset.neg = this.summary.neg;
this.dataset.untriaged = this.summary.untriaged;
this.dataset.num = this.summary.num;
this.loadedCount = 0;
if (this.triage && this.details) {
this.$.spinner.active = true;
this.$.counter.current = 0;
this.$.counter.max = this.summary.untHashes.length;
this.$.counter.active = true;
}
},
// filterNames removes all parameters with a key of 'name' from a param set query string.
filterNames: function(s) {
var o = sk.query.toParamSet(window.decodeURIComponent(s));
delete o["name"];
return window.encodeURIComponent(sk.query.fromParamSet(o));
},
formatPercent: function(prob) {
return (prob*100).toFixed(1);
}
});
</script>
</polymer-element>