blob: 18f943befb353b5181e84011d6d221fce5f8faf3 [file] [log] [blame]
/**
* @module modules/job-sk
* @description <h2><code>job-sk</code></h2>
*
* @evt
*
* @attr
*
* @example
*/
import { diffDate } from 'common-sk/modules/human';
import { define } from 'elements-sk/define';
import 'elements-sk/styles/table';
import 'elements-sk/styles/buttons';
import { html } from 'lit-html';
import { $$ } from 'common-sk/modules/dom';
import { ElementSk } from '../../../infra-sk/modules/ElementSk';
import {
GetTaskSchedulerService,
Job,
TaskSchedulerService,
GetJobResponse,
JobStatus,
CancelJobResponse,
} from '../rpc';
import { TaskGraphSk } from '../task-graph-sk/task-graph-sk';
import '../task-graph-sk';
import '../../../infra-sk/modules/human-date-sk';
import 'elements-sk/icon/delete-icon-sk';
import 'elements-sk/icon/search-icon-sk';
import 'elements-sk/icon/timeline-icon-sk';
const jobStatusToTextClass = new Map<JobStatus, [string, string]>();
jobStatusToTextClass.set(JobStatus.JOB_STATUS_IN_PROGRESS, [
'in progress',
'bg-in-progress',
]);
jobStatusToTextClass.set(JobStatus.JOB_STATUS_SUCCESS, [
'succeeded',
'bg-success',
]);
jobStatusToTextClass.set(JobStatus.JOB_STATUS_FAILURE, [
'failed',
'bg-failure',
]);
jobStatusToTextClass.set(JobStatus.JOB_STATUS_MISHAP, ['mishap', 'bg-mishap']);
jobStatusToTextClass.set(JobStatus.JOB_STATUS_CANCELED, [
'canceled',
'bg-canceled',
]);
export class JobSk extends ElementSk {
private static template = (ele: JobSk) => html`
<div>
<h2>Job ${ele.job!.name}</h2>
<button>
<timeline-icon-sk></timeline-icon-sk>
<a href="/job/${ele.job!.id}/timeline">View Timeline</a>
</button>
${ele.job!.status == JobStatus.JOB_STATUS_IN_PROGRESS
? html`
<button id="cancelButton" @click="${() => ele.cancel()}">
<delete-icon-sk></delete-icon-sk>
Cancel Job
</button>
`
: html``}
<table>
<tr>
<td>ID</td>
<td>${ele.job!.id}</td>
<td></td>
</tr>
<tr>
<td>Name</td>
<td>${ele.job!.name}</td>
<td>
<a
href="/jobs/search?name=${encodeURIComponent(ele.job!.name)}"
target="_blank"
>
<button><search-icon-sk></search-icon-sk>Search Jobs</button>
</a>
</td>
</tr>
<tr>
<td>Status</td>
<td class="${ele.statusClass}">${ele.statusText}</td>
<td></td>
</tr>
<tr>
<td>Requested</td>
<td>
<human-date-sk .date="${ele.job!.requestedAt!}"></human-date-sk>
</td>
<td></td>
</tr>
<tr>
<td>Created</td>
<td>
<human-date-sk .date="${ele.job!.createdAt!}"></human-date-sk>
</td>
<td></td>
</tr>
${ele.job!.finishedAt && new Date(ele.job!.finishedAt).getTime() > 0
? html`
<tr>
<td>Finished</td>
<td>
<human-date-sk .date="${ele.job!.finishedAt!}">
</human-date-sk>
</td>
<td></td>
</tr>
`
: html``}
<tr>
<td>Duration</td>
<td>${ele.duration}</td>
<td></td>
</tr>
<tr>
<td>Repo</td>
<td>
<a href="${ele.job!.repoState!.repo}" target="_blank">
${ele.job!.repoState!.repo}
</a>
</td>
<td></td>
</tr>
<tr>
<td>Revision</td>
<td>
<a href="${ele.revisionLink}" target="_blank">
${ele.job!.repoState!.revision}
</a>
</td>
<td>
<a
href="/jobs/search?revision=${encodeURIComponent(
ele.job!.repoState!.revision,
)}"
target="_blank"
>
<button><search-icon-sk></search-icon-sk>Search Jobs</button>
</a>
</td>
</tr>
${ele.isTryJob
? html`
<tr>
<td>Codereview Link</td>
<td>
<a href="${ele.codereviewLink}" target="_blank">
${ele.codereviewLink}
</a>
</td>
<td>
<a
href="/jobs/search?server=${encodeURIComponent(
ele.job!.repoState!.patch!.server,
)}&issue=${encodeURIComponent(
ele.job!.repoState!.patch!.issue,
)}&patchset=${encodeURIComponent(
ele.job!.repoState!.patch!.patchset,
)}"
target="_blank"
>
<button>
<search-icon-sk></search-icon-sk>Search Jobs
</button>
</a>
</td>
</tr>
<tr>
<td>Codereview Server</td>
<td>${ele.job!.repoState!.patch!.server}</td>
<td></td>
</tr>
<tr>
<td>Issue</td>
<td>${ele.job!.repoState!.patch!.issue}</td>
<td></td>
</tr>
<tr>
<td>Patchset</td>
<td>${ele.job!.repoState!.patch!.patchset}</td>
<td></td>
</tr>
`
: html``}
${ele.job!.buildbucketBuildId ? html`
<tr>
<td>Buildbucket Build ID</td>
<td>${ele.job!.buildbucketBuildId}</td>
<td></td>
</tr>
` : html``}
<tr>
<td>Manually forced</td>
<td>${ele.job!.isForce ? 'true' : 'false'}</td>
<td></td>
</tr>
</table>
</div>
<div>
<h2>Tasks</h2>
<task-graph-sk></task-graph-sk>
</div>
`;
private codereviewLink: string = '';
private duration: string = '';
private isTryJob: boolean = false;
private job: Job | null = null;
private revisionLink: string = '';
private _rpc: TaskSchedulerService | null = null;
private statusClass: string = '';
private statusText: string = '';
constructor() {
super(JobSk.template);
}
get jobID(): string {
return this.getAttribute('job-id') || '';
}
set jobID(jobID: string) {
this.setAttribute('job-id', jobID);
this.reload();
}
get swarming(): string {
return this.getAttribute('swarming') || '';
}
set swarming(swarming: string) {
this.setAttribute('swarming', swarming);
this._render();
}
get rpc(): TaskSchedulerService | null {
return this._rpc;
}
set rpc(rpc: TaskSchedulerService | null) {
this._rpc = rpc;
}
connectedCallback() {
super.connectedCallback();
this.rpc = GetTaskSchedulerService(this);
this.reload();
}
private updateFrom(job: Job) {
this.job = job;
const start = new Date(this.job.createdAt!);
const end = this.job.finishedAt && new Date(this.job.finishedAt).getTime() > 0
? new Date(this.job.finishedAt)
: new Date(Date.now()); // Use Date.now so that it can be mocked.
this.duration = diffDate(start.getTime(), end.getTime());
const rs = this.job.repoState!;
this.revisionLink = `${rs.repo}/+show/${rs.revision}`;
if (
rs.patch
&& rs.patch.issue != ''
&& rs.patch.patchset != ''
&& rs.patch.server != ''
) {
this.isTryJob = true;
const p = rs.patch!;
this.codereviewLink = `${p.server}/c/${p.issue}/${p.patchset}`;
}
[this.statusText, this.statusClass] = jobStatusToTextClass.get(
this.job.status,
)!;
this._render();
const graph = $$<TaskGraphSk>('task-graph-sk', this);
graph?.draw([this.job], this.swarming);
}
private reload() {
if (!this.jobID || !this.rpc) {
return;
}
this.rpc!.getJob({
id: this.jobID,
}).then((jobResp: GetJobResponse) => {
this.updateFrom(jobResp.job!);
});
}
private cancel() {
if (!this.job) {
return;
}
this.rpc
?.cancelJob({
id: this.job.id,
})
.then((resp: CancelJobResponse) => {
this.updateFrom(resp.job!);
});
}
}
define('job-sk', JobSk);