blob: c44d283cf2aa7f8cb7a82ccf5fefda5ba5023a60 [file] [log] [blame]
<!--
The common.js file must be included before this file.
This in an HTML Import-able file that contains the definition
of the following elements:
<arb-status-sk>
To use this file import it:
<link href="/res/imp/arb-status-sk.html" rel="import" />
Usage:
<arb-status-sk></arb-status-sk>
Properties:
reload - How often (in seconds) to reload data.
rollUser - User who creates the DEPS rolls.
Methods:
None.
Events:
None
-->
<link rel="import" href="/res/common/imp/human-date-sk.html">
<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-input/paper-input.html">
<link rel="import" href="/res/imp/bower_components/paper-spinner/paper-spinner.html">
<link rel="stylesheet" href="/res/common/css/md.css">
<dom-module id="arb-status-sk">
<style is="custom-style" include="iron-flex iron-flex-alignment iron-positioning">
:host {
font-family: sans-serif;
}
#loadstatus {
font-size: 0.8em;
padding: 0px 15px;
}
a,a.visited {
color: #1f78b4;
}
.table {
border-collapse: collapse;
display: table;
}
.tr {
border-bottom: 1px solid #EEEEEE;
display: table-row;
}
.tr:hover {
background-color: #F5F5F5;
}
.td,.th {
display: table-cell;
padding: 10px;
}
.td {
color: #212121;
font-size: 0.813em;
}
.th {
color: #767676;
font-size: 0.75em;
}
.success {
color: #66A61E;
}
.failure {
color: #D95F02;
}
.unknown {
color: #666666;
}
.big {
font-size: 1.3em;
}
.small {
font-size: 0.8em;
}
.nowrap {
white-space: nowrap;
}
.trybot {
margin: 5px;
}
</style>
<template>
<div class="horizontal layout center" id="loadstatus">
<paper-input type="number" value="{{reload}}" label="Reload (s)" prevent-invalid-input></paper-input>
<div class="flex"></div>
<div>Last loaded at <span>{{_lastLoaded}}</span></div>
</div>
<div id="statusDisplay">
<div class="table">
<div class="tr">
<div class="td nowrap">Mode:</div>
<div class="td nowrap">
<template is="dom-repeat" items="{{modeButtons}}">
<button class$="{{_buttonClass(item)}}" on-tap="_buttonPressed" disabled$="{{_modeChangePending}}">{{item.label}}</button>
</template>
<paper-spinner active$="{{_modeChangePending}}"></paper-spinner>
</div>
</div>
<div class="tr">
<div class="td nowrap">Status:</div>
<div class="td nowrap">
<span class$="{{_statusClass(status)}}"><span class="big">{{status}}</span></span>
</div>
</div>
<template is="dom-if" if="{{_computeShowError(_editRights,error)}}">
<div class="tr">
<div class="td nowrap">Error:</div>
<div class="td"><pre>{{error}}</pre></div>
</div>
</template>
<div class="tr">
<div class="td nowrap">Current Roll:</div>
<div class="td">
<div>
<template is="dom-if" if="{{_exists(currentRoll)}}">
<a href="{{_issueURL(currentRoll)}}" class="big" target="_blank">{{currentRoll.subject}}</a>
</template>
<template is="dom-if" if="{{!_exists(currentRoll)}}">
<span>(none)</span>
</template>
</div>
<div>
<template is="dom-repeat" items="{{currentRoll.tryResults}}">
<div class="trybot">
<template is="dom-if" if="{{_exists(item.url)}}">
<a href="{{item.url}}" class$="{{_trybotClass(item)}}" target="_blank">{{item.builder}}</a>
</template>
<template is="dom-if" if="{{!_exists(item.url)}}">
<span class="nowrap" class$="{{_trybotClass(item)}}">{{item.builder}}</span>
</template>
</div>
</template>
</div>
</div>
</div>
<template is="dom-if" if="{{_exists(lastRoll)}}">
<div class="tr">
<div class="td nowrap">Previous roll result:</div>
<div class="td">
<span class$="{{_rollClass(lastRoll)}}">{{_rollResult(lastRoll)}}</span>
<a href="{{_issueURL(lastRoll)}}" target="_blank" class="small">(detail)</a>
</div>
</div>
</template>
<div class="tr">
<div class="td nowrap">History:</div>
<div class="td">
<div class="table">
<div class="tr">
<div class="th">Roll</div>
<div class="th">Last Modified</div>
<div class="th">Result</div>
</div>
<template is="dom-repeat" items="{{recent}}">
<div class="tr">
<div class="td"><a href="{{_issueURL(item)}}" target="_blank">{{item.subject}}</a></div>
<div class="td"><human-date-sk date="{{item.modified}}" diff></human-date-sk> ago</div>
<div class="td"><span class$="{{_rollClass(item)}}">{{_rollResult(item)}}</span></div>
</div>
</template>
</div>
</div>
</div>
<div class="tr">
<div class="td nowrap">Full History:</div>
<div class="td">
<a href$="{{_rollUserURL}}" target="_blank">
{{_rollUserURL}}
</a>
</div>
</div>
</div>
</div>
</template>
<script>
Polymer({
is: 'arb-status-sk',
properties: {
mode: {
type: String,
value: "(not yet loaded)",
readOnly: true,
},
status: {
type: String,
value: "(not yet loaded)",
readOnly: true,
},
currentRoll: {
type: Object,
value: null,
readOnly: true,
},
error: {
type: String,
value: null,
readOnly: true,
},
lastRoll: {
type: Object,
value: null,
readOnly: true,
},
recent: {
type: Array,
value: function() { return []; },
readOnly: true,
},
reload: {
type: Number,
observer: "_reloadChanged",
value: 60,
},
rollUser: {
type: String,
value: "skia-deps-roller@chromium.org",
},
_rollUserURL: {
type: String,
computed: "_computeRollUserURL(rollUser)",
},
initialSelectedMode: {
type: Number,
value: 0,
readOnly: true,
},
modeButtons: {
type: Array,
value: function() { return []; },
readOnly: true,
},
validModes: {
type: Array,
value: function() { return []; },
readOnly: true,
},
_editRights: {
type: Boolean,
value: false,
},
_lastLoaded: {
type: String,
value: "not yet loaded",
},
_modeChangePending: {
type: Boolean,
value: false,
},
_timeout: {
type: Object,
value: null,
},
},
ready: function() {
sk.Login.then(function(status) {
this._editRights = status.IsAGoogler;
}.bind(this));
this._reload();
},
_buttonClass: function(mode) {
return mode.class;
},
_buttonLabel: function(mode) {
return mode.label;
},
_buttonPressed: function(e) {
if (!this._editRights) {
sk.errorMessage("You must be logged in with an @google.com account to set the ARB mode.");
return
}
var mode = e.srcElement.innerHTML;
if (mode == this.mode) {
return;
}
var url = "/json/mode";
var body = JSON.stringify({"mode": mode});
sk.errorMessage("Mode change in progress. This may take some time.");
this._modeChangePending = true;
sk.post(url, body).then(JSON.parse).then(function (json) {
this._update(json);
this._modeChangePending = false;
sk.errorMessage("Success!");
}.bind(this), function(err) {
this._modeChangePending = false;
sk.errorMessage("Failed to change the mode: " + err);
});
},
_computeRollUserURL: function(rollUser) {
return "https://codereview.chromium.org/user/" + rollUser;
},
_computeShowError: function(editRights, error) {
return editRights && error;
},
_issueURL: function(issue) {
if (issue) {
return "https://codereview.chromium.org/" + issue.issue;
}
},
_exists: function(obj) {
return !!obj;
},
_reloadChanged: function() {
this._resetTimeout();
},
_resetTimeout: function() {
if (this._timeout) {
window.clearTimeout(this._timeout);
}
if (this.reload > 0) {
this._timeout = window.setTimeout(function () {
this._reload();
}.bind(this), this.reload * 1000);
}
},
_reload: function() {
var url = "/json/status";
console.log("Loading status from " + url);
sk.get(url).then(JSON.parse).then(function(json) {
this._update(json);
}.bind(this)).catch(function(err) {
sk.errorMessage(err);
this._resetTimeout();
}.bind(this));
},
_rollClass: function(roll) {
if (!roll) {
return "unknown";
}
return {
"succeeded": "success",
"failed": "failure",
"in progress": "unknown",
"dry run succeeded": "success",
"dry run failed": "failure",
"dry run in progress": "unknown",
}[roll.result] || "unknown";
},
_rollResult: function(roll) {
if (!roll) {
return "unknown";
}
return roll.result;
},
_statusClass: function(status) {
return {
"error": "failure",
"in progress": "unknown",
"stopped": "failure",
"up to date": "success",
"dry run failed": "failure",
"dry run succeeded": "success",
"dry run in progress": "unknown",
}[status] || "";
},
_trybotClass: function(trybot) {
if (trybot.status == "STARTED") {
return "unknown";
} else if (trybot.status == "COMPLETED") {
return {
"CANCELED": "failure",
"FAILURE": "failure",
"SUCCESS": "success",
}[trybot.result] || "";
} else {
return "unknown";
}
},
_update: function(json) {
this._setCurrentRoll(json.currentRoll);
this._setError(json.error);
this._setLastRoll(json.lastRoll);
this._setMode(json.mode);
this._setRecent(json.recent);
this._setInitialSelectedMode(json.validModes.indexOf(json.mode).toString());
this._setStatus(json.status);
this._setValidModes(json.validModes);
var modeButtons = [];
for (var i = 0; i < this.validModes.length; i++) {
var m = this.validModes[i];
modeButtons.push({"label": m, "class": m == this.mode ? "action" : ""});
}
this._setModeButtons(modeButtons);
this._lastLoaded = new Date().toLocaleTimeString();
this._resetTimeout();
console.log("Reloaded status.");
},
});
</script>
</dom-module>