blob: 1419c1da1b0bcf12e8a0bb94b4103405532a10d7 [file] [log] [blame]
<!--
This in an HTML Import-able file that contains the definition
of the following elements:
<job-search-sk>
To use this file import it:
<link href="/res/imp/job-search-sk.html" rel="import" />
Usage:
<job-search-sk></job-search-sk>
Properties:
recent_repos: Array, optional list of repo URLs used for auto-completion.
recent_job_names: Array, optional list of job names used for auto-completion.
recent_commits: Array, optional list of commit hashes used for auto-completion.
recent_servers: Array, optional list of codereview servers used for auto-completion.
valid_statuses: Array, optional list of valid job statuses used for auto-completion.
Methods:
None.
Events:
None.
-->
<link rel="import" href="/res/common/imp/autocomplete-input-sk.html">
<link rel="import" href="/res/common/imp/date-time-picker-sk.html">
<link rel="import" href="/res/common/imp/human-date-sk.html">
<link rel="import" href="/res/common/imp/styles-sk.html">
<link rel="import" href="/res/common/imp/url-params-sk.html">
<link rel="import" href="/res/imp/bower_components/iron-collapse/iron-collapse.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/iron-icons/iron-icons.html">
<link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox.html">
<link rel="import" href="/res/imp/bower_components/paper-button/paper-button.html">
<link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html">
<link rel="import" href="/res/imp/bower_components/paper-icon-button/paper-icon-button.html">
<dom-module id="job-search-sk">
<template>
<style include="iron-flex iron-flex-alignment styles-sk">
:host {
font-family: sans-serif;
}
.cancelButton {
color: #fff;
}
.controlColumn {
width: 50%;
max-width: 500px;
padding: 5px;
}
.searchButton {
color: #fff;
}
.timeSelect {
padding: 3px;
}
</style>
<url-param-sk name="repo" value="{{repo}}"></url-param-sk>
<url-param-sk name="revision" value="{{revision}}"></url-param-sk>
<url-param-sk name="server" value="{{server}}"></url-param-sk>
<url-param-sk name="issue" value="{{issue}}"></url-param-sk>
<url-param-sk name="patchset" value="{{patchset}}"></url-param-sk>
<url-param-sk name="buildbucket_build_id" value="{{buildbucket_build_id}}"></url-param-sk>
<url-param-sk name="isForce" value="{{isForce}}"></url-param-sk>
<url-param-sk name="name" value="{{name}}"></url-param-sk>
<url-param-sk name="status" value="{{status}}"></url-param-sk>
<url-param-sk name="time_start" value="{{_time_start}}"></url-param-sk>
<url-param-sk name="time_end" value="{{_time_end}}"></url-param-sk>
<div class="container">
<div class="layout horizontal flex">
<div class="flex"><h2>Job Search</h2></div>
<paper-icon-button id="expandButton" icon="icons:arrow-drop-up" on-tap="_toggleExpand"></paper-icon-button>
</div>
<iron-collapse id="controls" opened>
<div class="layout horizontal">
<div class="controlColumn">
<div class="timeSelect">Start: <date-time-picker-sk format="ISO" value="{{_time_start}}"></date-time-picker-sk></div>
<div class="timeSelect">End: <date-time-picker-sk format="ISO" value="{{_time_end}}"></date-time-picker-sk></div>
<autocomplete-input-sk value="{{repo}}" label="Repo" autocomplete="[[recent_repos]]"></autocomplete-input-sk>
<autocomplete-input-sk value="{{revision}}" label="Revision" autocomplete="[[recent_commits]]"></autocomplete-input-sk>
<autocomplete-input-sk value="{{server}}" label="Server" autocomplete="[[recent_servers]]"></autocomplete-input-sk>
<paper-input value="{{issue}}" label="Issue"></paper-input>
</div>
<div class="controlColumn">
<autocomplete-input-sk value="{{patchset}}" label="Patchset"></autocomplete-input-sk>
<autocomplete-input-sk value="{{buildbucket_build_id}}" label="Buildbucket Build ID"></autocomplete-input-sk>
<div><paper-checkbox checked="{{isForce}}">Is Force</paper-input></div>
<autocomplete-input-sk value="{{name}}" label="Name" autocomplete="[[recent_job_names]]"></autocomplete-input-sk>
<autocomplete-input-sk value="{{status}}" label="Status" autocomplete="[[valid_statuses]]"></autocomplete-input-sk>
<div class="searchButton layout vertical center">
<paper-button on-tap="_search" class="searchButton bg-redorange" raised>Search</paper-button>
</div>
</div>
</div>
</iron-collapse>
</div>
<template is="dom-if" if="[[_showResults]]">
<div class="container">
<div class="table">
<div class="tr">
<div class="th">ID</div>
<div class="th">Name</div>
<div class="th">Repo</div>
<div class="th">Revision</div>
<div class="th">Codereview Link</div>
<div class="th">Status</div>
<div class="th">Manually Triggered</div>
<template is="dom-if" if="[[_editRights]]">
<div class="th">
<paper-button raised class="cancelButton bg-purple" on-tap="_cancelAll">Cancel All</paper-button>
</div>
</template>
</div>
<template is="dom-repeat" items="[[_results]]" as="job" initialCount="20">
<div class="tr">
<div class="td"><a href$="[[_jobLink(job)]]">[[job.id]]</a></div>
<div class="td">[[job.name]]</div>
<div class="td">[[job.repo]]</div>
<div class="td"><a href$="[[_revisionLink(job)]]" target="_blank">[[job.revision]]</a></div>
<div class="td">
<template is="dom-if" if="[[_isTryJob(job)]]">
<a href$="[[_codeReviewLink(job)]]" target="_blank">[[_codeReviewLink(job)]]</a>
</template>
</div>
<div class="td" style$="background-color:[[_statusColor(job)]]">[[_statusText(job)]]</div>
<div class="td">[[job.isForce]]</div>
<template is="dom-if" if="[[_editRights]]">
<div class="td">
<template is="dom-if" if="[[_showCancel(job)]]">
<paper-button raised class="cancelButton bg-purple" on-tap="_cancelJob" data-id$="[[job.id]]">Cancel</paper-button>
</template>
</div>
</template>
</div>
</template>
</div>
</div>
</template>
</template>
<script>
(function(){
var iconUp = "icons:arrow-drop-up";
var iconDown = "icons:arrow-drop-down";
var jobStatusToTextColor = {
"": ["in progress", "rgb(248, 230, 180)"],
"SUCCESS": ["succeeded", "rgb(209, 228, 188)"],
"FAILURE": ["failed", "rgb(217, 95, 2)"],
"MISHAP": ["mishap", "rgb(117, 112, 179)"],
"CANCELED": ["canceled", "rgb(117, 112, 179)"],
};
Polymer({
is: "job-search-sk",
properties: {
recent_repos: {
type: Array,
},
recent_job_names: {
type: Array,
},
recent_commits: {
type: Array,
},
recent_servers: {
type: Array,
},
valid_statues: {
type: Array,
},
// Private.
_editRights: {
type: Boolean,
},
_results: {
type: Array,
value: function() { return []; },
},
_showResults: {
type: Boolean,
},
_dropdownButtonIcon: {
type: String,
},
},
ready: function() {
sk.Login.then(function(status) {
var editRights = false;
var email = status["Email"];
if (email && email.endsWith("@google.com")) {
editRights = true;
}
this.set("_editRights", editRights)
}.bind(this));
// Only perform the initial search if URL params were specified for at
// least one search term.
if (window.location.search) {
this._search();
}
},
_search: function() {
var url = "/json/jobs/search" + window.location.search;
console.log("Searching Jobs from " + url);
this.set("_showResults", false);
this._toggleExpand();
sk.get(url).then(JSON.parse).then(function(json) {
this.set("_results", json);
this.set("_showResults", true);
}.bind(this)).catch(sk.errorMessage);
},
_toggleExpand: function() {
if (this.$.expandButton.icon === iconUp) {
this.$.expandButton.icon = iconDown;
} else {
this.$.expandButton.icon = iconUp;
}
this.$.controls.toggle();
},
_showCancel: function(job) {
return job.status === "";
},
_cancel: function(jobId) {
var url = "/json/job/" + jobId + "/cancel";
console.log("Canceling Job: " + url);
sk.post(url).then(JSON.parse).then(function(json) {
var idx = this._results.findIndex(function (job) {
return job.id === jobId;
});
if (idx != -1) {
this.splice("_results", idx, 1, json);
}
}.bind(this)).catch(sk.errorMessage);
},
_cancelJob: function(e) {
this._cancel(e.target.dataset.id);
},
_cancelAll: function() {
var toCancel = this._results.filter(function(job) {
return job.status === "";
});
if (!toCancel.length) {
sk.errorMessage("No unfinished jobs to cancel!");
return;
}
for (var i = 0; i < toCancel.length; i++) {
this._cancel(toCancel[i].id);
}
},
_codeReviewLink: function(job) {
return job.server + "/c/" + job.issue + "/" + job.patchset;
},
_isTryJob: function(job) {
return job.server != "" && job.issue != "" && job.patchset != "";
},
_jobLink: function(job) {
return "/job/" + job.id;
},
_revisionLink: function(job) {
// This assumes we use Gitiles, but that's a safe assumption for now.
return job.repo + "/+/" + job.revision;
},
_statusText: function(job) {
if (!job || job.status === undefined || job.status === null) {
return "unknown";
}
var textColor = jobStatusToTextColor[job.status];
if (!textColor || textColor.length != 2) {
return "unknown";
}
return textColor[0];
},
_statusColor: function(job) {
if (!job || job.status === undefined || job.status === null) {
return "rgb(255, 255, 255)";
}
var textColor = jobStatusToTextColor[job.status];
if (!textColor || textColor.length != 2) {
return "rgb(255, 255, 255)";
}
return textColor[1];
},
});
})();
</script>
</dom-module>