blob: 515b131085d8d77c4c79838a10919980147b1e29 [file] [log] [blame]
<!-- The <cluster-page-sk> custom element declaration.
The top level element for clustering traces.
Attributes:
None.
Events:
None.
Methods:
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-checkbox/paper-checkbox.html">
<link rel="import" href="/res/imp/bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html">
<link rel="import" href="/res/imp/bower_components/iron-selector/iron-selector.html">
<link rel="import" href="/res/common/imp/details-summary.html">
<link rel="import" href="/res/common/imp/sort.html" />
<link rel="stylesheet" href="/res/common/css/md.css">
<dom-module id="cluster-page-sk">
<style include="iron-flex iron-flex-alignment iron-positioning">
day-range-sk {
display: block;
}
label {
width: 4em;
display: inline-block;
text-align: right;
}
#status {
display: inline-block;
margin: 0.5em;
}
cluster-summary2-sk {
box-shadow: 4px 4px 10px 1px rgba(0,0,0,0.75);
display: block;
padding: 1em;
margin: 1em;
width: 80em;
}
#advanced h2 {
display: inline-block;
margin: 0;
}
#advanced {
height: 2em;
display: inline-block;
vertical-align: bottom;
}
#inputs {
margin-left: 2em;
}
#inputs paper-input {
width: 20em;
}
.iron-selected {
background: #eee;
}
iron-selector div {
width: 10em;
margin: 0.3em 1em;
padding: 0.2em;
}
.info {
margin: 1em;
font-size: 18px;
color: #E7298A;
}
paper-checkbox {
--paper-checkbox-checked-color: #1f78b4;
--paper-checkbox-checked-ink-color: #1f78b4;
}
algo-select-sk {
width: 20em;
display: block;
}
</style>
<template>
<h2>Commit</h2>
<h3>Appears in Date Range</h3>
<div class="layout horizontal">
<day-range-sk id=range on-day-range-change="_rangeChange"></day-range-sk>
<paper-spinner id=spinner></paper-spinner>
</div>
<h3>Commit</h3>
<div>
<commit-detail-picker-sk on-commit-selected="_commitSelected" id=commit></commit-picker-sk>
</div>
<h2>Algorithm</h2>
<algo-select-sk on-algo-change=_algoChange algo="[[state.algo]]"></algo-select-sk>
<h2>Query</h2>
<div class="layout horizontal">
<query-sk id=query on-query-change="_queryChange" on-query-change-delayed="_queryChangeDelayed"></query-sk>
<div class="layout vertical" id=selections>
<h3>Selections</h3>
<query-summary-sk id=summary></query-summary-sk>
<div>
Matches: <span id=matches></span>
</div>
<button on-tap="_start" class=action id=start>Run</button>
<div class="layout horizontal center">
<paper-spinner id=clusterSpinner></paper-spinner>
<span id=status></span>
</div>
</div>
</div>
<details-sk>
<summary-sk id=advanced>
<h2>Advanced</h2>
</summary-sk>
<div id=inputs>
<paper-input type=number min=0 max=100 value="{{state.k}}" label="K (A value of 0 means the server chooses)."></paper-input>
<paper-input type=number min=1 max=25 value="{{state.radius}}" label="Number of commits to include on either side."></paper-input>
<paper-input type=number min=0 max=500 value="{{state.interesting}}" label="Clusters are interesting if regression score >= this."></paper-input>
<paper-checkbox checked="{{state.sparse}}">Data is sparse, so only include commits that have data.</paper-checkbox>
</div>
</details-sk>
<h2>Results</h2>
<sort-sk target=clusters node_name="CLUSTER-SUMMARY2-SK">
<button data-key="clustersize">Cluster Size </button>
<button data-key="stepregression" data-default=up>Regression </button>
<button data-key="stepsize">Step Size </button>
<button data-key="steplse">Least Squares</button>
</sort-sk>
<div id=clusters>
<template id=results is="dom-repeat" items="{{_summaries}}">
<cluster-summary2-sk full_summary="[[item]]" notriage></cluster-summary2-sk>
</template>
<template is="dom-if" if="{{_isZeroLength(_summaries,_requestId)}}">
<p class=info>
No clusters found.
</p>
</template>
</div>
</template>
</dom-module>
<script>
Polymer({
is: "cluster-page-sk",
properties: {
_dataframe: {
type: Object,
value: function() { return {
traceset: {},
}; },
},
// Keep track of whether a request is inflight to count the number of traces that match the current query.
_countInProgress: {
type: Boolean,
value: false,
},
// The state that goes into the URL.
//
state: {
type: Object,
value: function() { return {
begin: Math.floor(Date.now()/1000 - 24*60*60),
end: Math.floor(Date.now()/1000),
source: "",
offset: -1,
radius: "" + sk.perf.radius,
query: "",
k: "" + 0,
algo: "kmeans",
interesting: "" + sk.perf.interesting,
sparse: false,
}; },
},
// The id of the current cluster request. Will be the empty string
// if there is no pending request.
_requestId: {
type: String,
value: "",
},
_cids: {
type: Array,
value: function() { return [] },
},
// Keep track of whether a request is inflight to count the number of traces that match the current query.
_countInProgress: {
type: Boolean,
value: false,
},
_requestId: {
type: String,
value: "",
}
},
ready: function() {
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
sk.get("/_/initpage/?tz=" + tz).then(JSON.parse).then(function(json) {
this.$.query.key_order = sk.perf.key_order;
this.$.query.paramset = json.dataframe.paramset;
}.bind(this)).catch(sk.errorMessage);
// From this point on reflect the state to the URL.
sk.stateReflector(this, this._updateCommitSelections.bind(this));
this.$.clusters.addEventListener("open-keys", function(e) {
var query = {
keys: e.detail.shortcut,
begin: e.detail.begin,
end: e.detail.end,
xbaroffset: e.detail.xbar.offset,
num_commits: 50,
request_type: 1,
};
window.open('/e/?' + sk.query.fromObject(query), '_blank');
}.bind(this));
},
// _catch for sk.post and sk.get requests around clustering.
_catch: function(msg) {
this._requestId = "";
this.$.clusterSpinner.active = false;
this.$.start.disabled = false;
if (msg) {
sk.errorMessage(msg, 10000);
}
this.$.status.textContent = "";
},
_start: function() {
if (this._requestId != "") {
sk.errorMessage("There is a pending query already running.");
return
}
var body = {
source: this.state.source,
offset: this.state.offset,
radius: +this.state.radius,
query: this.state.query,
k: +this.state.k,
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
algo: this.state.algo,
interesting: +this.state.interesting,
sparse: this.state.sparse,
};
this._summaries = [];
this.$.results.render();
this.$.clusterSpinner.active = true;
this.$.start.disabled = true;
sk.post("/_/cluster/start", JSON.stringify(body), "application/json").then(JSON.parse).then(function(json) {
this._requestId = json.id;
this._checkClusterRequestStatus(function(summaries) {
var fullSummaries = [];
summaries.summary.Clusters.forEach(function(cl) {
cl.ID = -1;
fullSummaries.push({
summary: cl,
frame: summaries.frame,
});
});
this.set('_summaries', fullSummaries);
}.bind(this));
}.bind(this)).catch(this._catch.bind(this));
},
_algoChange: function(e) {
this.state.algo = e.detail.algo;
},
_checkClusterRequestStatus: function(cb) {
sk.get("/_/cluster/status/"+this._requestId).then(JSON.parse).then(function(json) {
if (json.state == "Running") {
this.$.status.textContent = json.message;
window.setTimeout(this._checkClusterRequestStatus.bind(this, cb), 300);
} else {
if (json.value) {
cb(json.value);
}
this._catch(json.message);
}
}.bind(this)).catch(this._catch.bind(this));
},
_updateCommitSelections: function() {
this.$.range.begin = this.state.begin;
this.$.range.end = this.state.end;
this.$.query.current_query = this.state.query;
var body = {
begin: this.state.begin,
end: this.state.end,
source: this.state.source,
offset: this.state.offset,
};
this.$.spinner.active = true;
sk.post("/_/cidRange/", JSON.stringify(body), "application/json").then(JSON.parse).then(function(cids) {
this.$.spinner.active = false;
cids.reverse();
this._cids = cids;
this.$.commit.details = cids;
var index = -1;
// Look for commit id in this._cids.
for (var i = 0; i < cids.length; i++) {
if (cids[i].source == this.state.source && cids[i].offset == this.state.offset) {
index = i;
break
}
}
// If there is then select via index.
if (index != -1) {
this.$.commit.selected = index;
}
if (this.state.begin == 0) {
this.state.begin = cids[cids.length-1].ts;
this.$.range.begin = cids[cids.length-1].ts;
this.state.end = cids[0].ts;
this.$.range.end = cids[0].ts;
}
}.bind(this)).catch(function(msg) {
if (msg) {
sk.errorMessage(msg, 10000);
}
this.$.spinner.active = false;
}.bind(this));
this._updateCount();
},
_commitSelected: function(e) {
this.state.source = e.detail.commit.source;
this.state.offset = e.detail.commit.offset;
},
_queryChange: function(e) {
this.state.query = e.detail.q;
this.$.summary.selection = e.detail.q;
},
_queryChangeDelayed: function(e) {
this._updateCount();
},
_rangeChange: function(e) {
if (!this.state) {
return
}
this.state.begin = e.detail.begin;
this.state.end = e.detail.end;
this._updateCommitSelections();
},
_updateCount: function() {
if (this._countInProgress === true) {
return
}
this._countInProgress = true;
let body = {
q: this.$.query.current_query,
begin: this.state.begin,
end: this.state.end,
};
sk.post("/_/count/", JSON.stringify(body)).then(JSON.parse).then(function(json) {
this._countInProgress = false;
this.$.matches.textContent = json.count;
if (json.paramset) {
this.$.query.paramset = json.paramset;
}
}.bind(this)).catch(function() {
this._countInProgress = false;
});
},
_isZeroLength: function(ar, _requestId) {
return ar.length == 0 && this._requestId == "";
}
});
</script>