| <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> |