blob: 35ee99a03d167515fd2c593aec7de42c0f003aaa [file] [log] [blame]
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="../../bower_components/app-layout/app-scroll-effects/app-scroll-effects.html">
<link rel="import" href="../../bower_components/app-layout/app-header/app-header.html">
<link rel="import" href="../../bower_components/app-layout/app-header-layout/app-header-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../bower_components/paper-item/paper-item-body.html">
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-if.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-repeat.html">
<link rel="import" href="../../bower_components/app-route/app-location.html">
<link rel="import" href="../../bower_components/app-route/app-route.html">
<dom-module id="build-status">
<template>
<app-location route="{{route}}" use-hash-as-path></app-location>
<app-route route="{{route}}"
pattern=":project_name"
data="{{routeData}}">
</app-route>
<style is="custom-style" include="iron-flex iron-flex-alignment">
<style>
.paper-item-link {
color: inherit;
text-decoration: none;
}
app-header {
background-color: #2ba4ad;
color: #fff;
}
paper-card {
margin: 0.5em;
}
paper-item {
cursor: pointer;
}
paper-tabs {
-webkit-font-smoothing: antialiased;
width: 100%;
margin-bottom: 1px;
height: 40px;
}
:host {
display: block;
}
.icon-error {
color: #e83030;
margin-right: 0.2em;
}
.projects {
min-width: 10em;
}
.log {
width: 80%;
display: inline;
}
pre {
white-space: pre-wrap;
}
</style>
<app-header reveals>
<app-toolbar>
<div main-title>OSS-Fuzz build status</div>
<div><small>(Updated every 30 minutes)</small></div>
</app-toolbar>
</app-header>
<div class="layout horizontal">
<paper-card class="projects">
<div class="card-tabs">
<paper-tabs selected="fuzzing" id="build_type" attr-for-selected="type" on-click="onChanged">
<paper-tab type="fuzzing">Fuzzing Builds</paper-tab>
<paper-tab type="coverage">Coverage Builds</paper-tab>
</paper-tabs>
</div>
<div class="card-content">
<template is="dom-repeat" items="[[status.projects]]" as="project">
<paper-item on-tap="onTap">
<paper-item-body two-line>
<div>
<template is="dom-if" if="[[!project.success]]">
<iron-icon class="icon-error" icon="icons:error"></iron-icon>
</template>
[[project.name]]
</div>
<div secondary title$="Last built [[toLocalDate(project.finish_time)]]">
Last built [[toLocalDate(project.finish_time)]]
</div>
</paper-item-body>
</paper-item>
</template>
</div>
</paper-card>
<paper-card class="log">
<div class="card-content">
<template is="dom-if" if="[[showMessage(loading_log, log)]]">
Select a project to see logs.
</template>
<template is="dom-if" if="[[loading_log]]">
Loading...
</template>
<template is="dom-if" if="[[showLog(log)]]">
<a href="/log-[[build_id]].txt" tabindex="-1">
<iron-icon icon="icons:link"></iron-iron>
</a>
</template>
<pre>[[log]]</pre>
</div>
</paper-card>
</div>
<iron-ajax id="status_fuzzing" auto handle-as="json" url="/status.json" on-response="onResponseForFuzzing"></iron-ajax>
<iron-ajax id="status_coverage" auto handle-as="json" url="/status-coverage.json" on-response="onResponseForCoverage"></iron-ajax>
<iron-ajax id="logxhr" auto handle-as="text" on-response="onLogResponse"></iron-ajax>
</template>
<script>
/** @polymerElement */
class BuildStatus extends Polymer.Element {
static get is() { return 'build-status'; }
static get properties() {
return {
log: {
type: String,
value: ''
},
loading_log: {
type: Boolean,
value: false
}
};
}
static get observers() {
return [
'_routeChanged(route.*)'
];
}
_routeChanged() {
if (!this.status || !this.routeData.project_name) {
// If our status json is loaded and there is a project_name specified
// in the URL, we can proceed to load that project's log.
return;
}
var project = this.getProjectByName(this.routeData.project_name);
this.$.logxhr.url = "/log-" + project.build_id + ".txt";
this.build_id = project.build_id;
this.log = '';
this.loading_log = true;
}
getProjectByName(project_name) {
return this.status.projects.find(p => p.name === project_name);
}
onResponseForFuzzing(e) {
this.status_fuzzing = e.detail.response;
if (!this.status) {
// Show status of the fuzzing builds by default.
this.status = this.status_fuzzing;
// Manually invoke a _routeChanged call, in order to load the log for
// someone going directly to a project's URL.
this._routeChanged();
}
}
onResponseForCoverage(e) {
this.status_coverage = e.detail.response;
}
onLogResponse(e) {
this.log = e.detail.response;
this.loading_log = false;
}
onTap(e) {
// Change the route, this should auto-magically update the url in the
// browser and invoke the _routeChanged method.
this.set('route.path', e.model.project.name);
}
onChanged(e) {
if (this.$.build_type.selected == 'coverage') {
this.status = this.status_coverage
} else {
this.status = this.status_fuzzing
}
}
showMessage(loading_log, log) {
return !loading_log && log === '';
}
showLog(log) {
return log !== '';
}
toLocalDate(str) {
let date = new Date(str);
let ds = date.toString();
let timezone = ds.substring(ds.indexOf("("));
return date.toLocaleString() + " " + timezone;
}
};
window.customElements.define(BuildStatus.is, BuildStatus);
</script>
</dom-module>