blob: cc14683ce69c22c4833a1568bf537816d5351275 [file] [log] [blame]
<!--
This in an HTML Import-able file that contains the definitions
for the following elements:
<cluster-summary-sk>
Properties:
fade - A boolean, fade out an issue if its status isn't New.
mailbox - The name of the sk.Mailbox that contains a serialized
tiling.TileGUI.
Methods:
setSummary() - A serialized types.ClusterSummary.
If the summary.ID == -1 then the triaging dialog is not displayed.
Events:
None.
-->
<link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="/res/imp/bower_components/paper-material/paper-material.html">
<link rel="import" href="/res/imp/bower_components/paper-radio-button/paper-radio-button.html">
<link rel="import" href="/res/imp/bower_components/paper-radio-group/paper-radio-group.html">
<link rel="stylesheet" href="/res/common/css/md.css">
<link rel="import" href="/res/common/imp/login.html">
<link rel="import" href="/res/common/imp/toggle.html">
<link rel="import" href="/res/common/imp/word-cloud.html">
<link rel="import" href="plot.html">
<dom-module id="cluster-summary-sk">
<style include="iron-flex iron-flex-alignment">
#status.disabled {
opacity: 0.5;
}
.highlight .high {
background-color: #44AA99;
color: white;
border-radius: 6px;
padding: 3px 6px;
}
.highlight .low {
background-color: #AA4499;
color: white;
border-radius: 6px;
padding: 3px 6px;
}
@media (max-width: 600px) {
#graph {
display: none;
}
}
.fade {
opacity: 0.3;
}
word-cloud-sk {
display: none;
}
word-cloud-sk.display {
display: block;
}
.disabledMessage {
display: none;
}
#status {
padding: 0.5em 2em;
}
#status.disabled .disabledMessage {
display: block;
}
plot-simple-sk {
margin: 1em;
}
paper-material #status.hidden,
#clPermalink.hidden {
display: none;
}
#choices paper-radio-button {
--default-primary-color: #1f78b4;
}
input {
padding: 0.6em;
}
.labelled {
display: inline-block;
margin-right: 2em;
}
</style>
<template>
<div id=container class$="layout horizontal {{faded(fade, summary.Status)}}">
<plot-sk id=graph width=400 height=150></plot-sk>
<div class="clDetails highlight">
<p class$="{{statusClass(summary.StepFit.Status)}}">
Regression: <span class="clRegression">{{trunc(summary.StepFit.Regression)}}</span>
</p>
<p>
<button id="shortcut">View on dashboard</button>
<a id="clPermalink" class$="{{hiddenClass(summary.ID)}}" href$="{{permaLink(summary.ID)}}">Permlink</a>
</p>
<p id=metrics>
<div class=labelled>Cluster Size: <span class="clClusterSize">{{summary.Keys.length}}</span></div>
<div class=labelled>Least Squares Error: <span class="clLeastSquares">{{trunc(summary.StepFit.LeastSquares)}}</span></div>
<div class=labelled>Step Size: <span class="clStepSize">{{trunc(summary.StepFit.StepSize)}}</span></div>
<div class=labelled><span class="clBugs">Bugs:</span></div>
<div class=labelled>Commit: <a href$="{{commitLink(summary.Hash)}}">{{truncHash(summary.Hash)}}</a></div>
</p>
<template is="dom-repeat" items="{{summary.Bugs}}" as="b">
<a class="clBug" href$="{{bugLink(b)}}">{{b}}</a>&nbsp;
</template>
<paper-material elevation="1">
<div id=status class$="{{hiddenClassDisabled(summary.ID)}}">
<p class="disabledMessage">You must be logged in to change the status.</p>
<paper-radio-group id=choices class="layout horizontal" selected="{{cachedStatus}}">
<b class="status">Status:</b>
<paper-radio-button name="New" label="New">New</paper-radio-button>
<paper-radio-button name="Ignore" label="Ignore">Ignore</paper-radio-button>
<paper-radio-button name="Bug" label="Bug">Bug</paper-radio-button>
</paper-radio-group>
<input value="{{summary.Message}}" label="Note" id="message"></input>
<button class="action layout self end" id=update>Update</button>
</div>
</paper-material>
<toggle-display-sk>Word Cloud</toggle-display-sk>
<word-cloud-sk id=wordcloud></word-cloud-sk>
</div>
</div>
</template>
<script>
Polymer({
is: 'cluster-summary-sk',
properties: {
fade: {
type: Boolean,
value: false,
},
mailbox: {
type: String,
value: "tileinfo",
},
},
ready: function () {
this.summary = {};
this.tileinfo = {};
this.$.update.addEventListener('click', this.updateClick.bind(this));
this.$.shortcut.addEventListener('click', this.openShortcut.bind(this));
this.cachedStatus = this.summary.Status || 'New';
sk.Login.then(function(status) {
this.$.status.classList.toggle('disabled', status['Email'] == '');
}.bind(this)).catch(sk.errorMessage);
sk.Mailbox.subscribe(this.mailbox, function(tileinfo) {
if (!tileinfo) {
return
}
this.tileinfo = tileinfo;
this.setGraphInfo();
}.bind(this));
},
setGraphInfo: function() {
if (!this.summary["Hash"] || !this.tileinfo["commits"]) {
return
}
// this.$.graph.setBackgroundInfo();
// this.$.graph.setStepIndex(); uses this.summary.Hash.
var skps = [0].concat(this.tileinfo.skps, [this.tileinfo.commits.length-1]);
var tickmap = {};
for (var i = this.tileinfo.ticks.length - 1; i >= 0; i--) {
var t = this.tileinfo.ticks[i];
tickmap[t[0]] = t[1];
}
this.$.graph.setBackgroundInfo(tickmap, skps, this.lastCommitIndex(this.tileinfo.commits));
var index = -1;
for (var i = 0, len = this.tileinfo.commits.length; i < len; i++) {
if (this.tileinfo.commits[i].hash == this.summary.Hash) {
index = i;
break;
}
}
this.$.graph.setStepIndex(index);
},
lastCommitIndex: function(commits) {
for (var i = commits.length - 1; i >= 0; i--) {
if (commits[i].commit_time != 0) {
return i;
}
}
// We shouldn't get here.
return commits.length-1;
},
setSummary: function (summary) {
// Check for an empty summary object.
if (summary.ParamSummaries == undefined) {
return;
}
this.summary = summary;
this.cachedStatus = this.summary.Status || 'New';
// Set the data- attributes used for sorting cluster summaries.
this.dataset.clustersize = this.summary.Keys.length;
this.dataset.steplse = this.summary.StepFit.LeastSquares;
this.dataset.stepsize = this.summary.StepFit.StepSize;
this.dataset.stepregression = this.summary.StepFit.Regression;
this.dataset.timestamp = this.summary.Timestamp;
this.summary.ParamSummaries.sort(function (a, b) {
return b[0].Weight - a[0].Weight;
});
this.$.wordcloud.setItems(summary.ParamSummaries);
// We take in a ClusterSummary, but need to transform all that data
// into a format that plot-sk can handle.
// Covert this.summary.Traces[0] into a traces that plot-sk wants.
var traces = [
{
data: this.summary.Traces[0],
label: "0",
_params: {"id": "0"},
},
];
this.$.graph.addTraces(traces);
this.$.graph.highlightGroup("id", "0");
this.setGraphInfo();
},
updateClick: function () {
var status = this.$.choices.selected;
var state = {
Id: this.summary.ID,
Status: status,
Message: this.$.message.value
};
sk.post('/annotate/', JSON.stringify(state)).then(JSON.parse).then(function (json) {
this.set("summary.Status", status);
if (json.Bug) {
// Open the bug reporting page in a new window.
window.open(json.Bug, '_blank');
}
}.bind(this)).catch(sk.errorMessage);
},
openShortcut: function (e) {
var keys = this.summary.Keys.slice(0, 50);
var state = {
scale: 0,
tiles: [-1],
hash: this.summary.Hash,
keys: keys,
};
sk.post('/shortcuts/', JSON.stringify(state)).then(JSON.parse).then(function (json) {
window.open('/#' + json.id, '_blank');
});
e.preventDefault();
},
// Below are filters used in template expansion:
hiddenClass: function (id) {
if (id == -1) {
return 'hidden';
}
return '';
},
hiddenClassDisabled: function (id) {
if (id == -1) {
return 'hidden';
}
return '';
},
permaLink: function (id) {
return '/cl/' + id;
},
faded: function (fade, status) {
if (fade && status != 'New') {
return 'fade';
}
return '';
},
statusClass: function (status) {
status = status || "";
return status.toLowerCase();
},
trunc: function (value) {
return (+value).toPrecision(3);
},
truncHash: function (value) {
if (value) {
return value.substring(0, 7);
}
},
commitLink: function (hash) {
return 'https://skia.googlesource.com/skia/+/' + hash;
},
bugLink: function (b) {
return 'https://bug.skia.org/' + b;
}
});
</script>
</dom-module>