blob: 48a37331f44840c85bc291527a2a7b4f4102cfdc [file] [log] [blame]
/**
* @module module/leasing-selections-sk
* @description <h2><code>leasing-selections-sk</code></h2>
*
* <p>
* Contains the selections the user needs to make to schedule a leasing
* swarming task.
* </p>
*
*/
import { define } from 'elements-sk/define';
import { html, TemplateResult } from 'lit-html';
import { $$ } from 'common-sk/modules/dom';
import 'elements-sk/error-toast-sk';
import 'elements-sk/icon/folder-icon-sk';
import 'elements-sk/icon/gesture-icon-sk';
import 'elements-sk/icon/help-icon-sk';
import 'elements-sk/icon/home-icon-sk';
import 'elements-sk/icon/star-icon-sk';
import 'elements-sk/nav-button-sk';
import 'elements-sk/nav-links-sk';
import 'elements-sk/select-sk';
import 'elements-sk/styles/select';
import { errorMessage } from 'elements-sk/errorMessage';
import { ElementSk } from '../../../infra-sk/modules/ElementSk';
import { device, getAKAStr, doImpl } from '../leasing';
import '../../../infra-sk/modules/login-sk';
import { Task, PoolDetails } from '../json';
export class LeasingSelectionsSk extends ElementSk {
private all_pools: string[] = ['Skia'];
private pool: string = 'Skia';
private osTypes: { [key: string]: number; } = {};
private deviceTypes: Record<string, string> = {};
private selectedDeviceType: string = '';
private selectedOsType: string = '';
private osToDeviceTypes: { [key: string]: { [key: string]: number } | null } = {};
private loadingDetails: boolean = false;
constructor() {
super(LeasingSelectionsSk.template);
this.fetchSupportedPools();
this.fetchOsDetails();
}
private static template = (ele: LeasingSelectionsSk) => html`
<table class="options panel">
<tr>
<td class="step-title">Select Pool</td>
<td>
<select id="pool" ?disabled=${ele.loadingDetails} .selection=${ele.pool} @input=${ele.poolChanged}>
${LeasingSelectionsSk.displayPools(ele)}
</select>
</td>
</tr>
<tr>
<td class="step-title">Select OS Type</td>
<td>
<select id="os_type" ?disabled=${ele.loadingDetails} @input=${ele.osTypeChanged}>
${LeasingSelectionsSk.displayOsTypes(ele)}
</select>
</td>
</tr>
<tr>
<td class="step-title">Select Device Type</td>
<td>
<select id="device_type" ?disabled=${ele.loadingDetails || (ele.selectedOsType !== 'Android' && !ele.selectedOsType.startsWith('iOS'))}>
${LeasingSelectionsSk.displayDeviceTypes(ele)}
</select>
</td>
</tr>
<tr>
<td class="step-title">Specify BotId (optional)</td>
<td>
<input id="bot_id" ?disabled=${ele.loadingDetails}></input>
<br/>
<span class="smaller-font">Note: OS Type and Device Type are ignored if this is populated</span>
</td>
</tr>
<tr>
<td class="step-title">Specify Swarming Task Id<br/>to keep artifacts ready on bot<br/>(optional)</td>
<td>
<input id="task_id" ?disabled=${ele.loadingDetails}></input>
</td>
</tr>
<tr>
<td class="step-title">Lease Duration</td>
<td>
<select id="duration" ?disabled=${ele.loadingDetails}>
<option value="1" title="1 Hour">1hr</option>
<option value="2" title="2 Hours">2hr</option>
<option value="6" title="6 Hours">6hr</option>
<option value="23" title="23 Hours">23hr</option>
</select>
</td>
<tr>
<td class="step-title">Description</td>
<td>
<input id="desc" ?disabled=${ele.loadingDetails} placeholder="Description is required"></input>
</td>
</tr>
<tr>
<td colspan="2" class="center">
<button raised @click=${ele.addTask} ?disabled=${ele.loadingDetails}>Lease Bot</button>
</td>
</tr>
</table>
`;
private static displayPools(ele: LeasingSelectionsSk): TemplateResult[] {
return ele.all_pools.map((p) => html`
<option
?selected=${ele.pool === p}
value=${p}
title=${p}
>${p}
</option>`);
}
private static displayOsTypes(ele: LeasingSelectionsSk): TemplateResult[] {
if (Object.keys(ele.osTypes).length === 0) {
return [html``];
}
return Object.keys(ele.osTypes).map((o) => html`
<option
value=${o}
title=${o}
>${o} - ${ele.osTypes[o]} bots online
</option>`);
}
private static displayDeviceTypes(ele: LeasingSelectionsSk): TemplateResult[] {
if (Object.keys(ele.osToDeviceTypes).length === 0) {
return [html``];
}
if (!(ele.selectedOsType in ele.osToDeviceTypes)) {
return [html``];
}
const deviceTypes = ele.osToDeviceTypes[ele.selectedOsType] || {};
return Object.keys(deviceTypes).map((d) => html`
<option
value=${d}
title=${d}
>${device(d)} ${getAKAStr(d)} - ${deviceTypes[d]} bots online
</option>`);
}
connectedCallback(): void {
super.connectedCallback();
this._render();
}
disconnectedCallback(): void {
super.disconnectedCallback();
}
private poolChanged(e: InputEvent): void {
this.pool = (e.target! as HTMLInputElement).value;
this.fetchOsDetails();
}
private osTypeChanged(e: InputEvent): void {
this.selectedOsType = (e.target! as HTMLInputElement).value;
this._render();
}
private fetchSupportedPools(): void {
doImpl('/_/get_supported_pools', {}, (json) => {
this.all_pools = json;
this._render();
});
}
private fetchOsDetails(): void {
doImpl(`/_/pooldetails?pool=${this.pool}`, {}, (json: PoolDetails) => {
this.osTypes = json.os_types || {};
this.osToDeviceTypes = json.os_to_device_types || {};
// Select first OsType.
this.selectedOsType = Object.keys(this.osTypes)[0];
this._render();
});
}
private addTask(): void {
const pool = ($$('#pool', this) as HTMLInputElement).value;
const osType = ($$('#os_type', this) as HTMLInputElement).value;
const deviceType = ($$('#device_type', this) as HTMLInputElement).value;
const botId = ($$('#bot_id', this) as HTMLInputElement).value;
const taskId = ($$('#task_id', this) as HTMLInputElement).value;
const duration = ($$('#duration', this) as HTMLInputElement).value;
const desc = ($$('#desc', this) as HTMLInputElement).value;
// Validate inputs.
if (!desc) {
errorMessage('Please specify a description');
return;
}
// Confirm.
const confirmed = window.confirm('Proceed with adding leasing task?');
if (!confirmed) {
return;
}
// Call backend to add task.
const detail = {} as Task;
detail.pool = pool;
detail.botId = botId;
if (!botId) {
detail.osType = osType;
if (deviceType) {
detail.deviceType = deviceType;
}
}
detail.taskIdForIsolates = taskId;
detail.duration = duration;
detail.description = desc;
this.loadingDetails = true;
this._render();
doImpl('/_/add_leasing_task', detail, () => {
window.location.href = '/my_leases';
});
}
/** @prop appTitle {string} Reflects the app_title attribute for ease of use. */
get appTitle(): string { return this.getAttribute('app_title')!; }
set appTitle(val: string) { this.setAttribute('app_title', val); }
}
define('leasing-selections-sk', LeasingSelectionsSk);