blob: 49915a606b3b246f6796a23c9267c0cb20553177 [file] [log] [blame]
import '../../../infra-sk/modules/app-sk'
import 'elements-sk/error-toast-sk'
import { errorMessage } from 'elements-sk/errorMessage'
import { diffDate } from 'common-sk/modules/human'
import { jsonOrThrow } from 'common-sk/modules/jsonOrThrow'
import { define } from 'elements-sk/define'
import { html, render } from 'lit-html'
// How often to update the data.
const UPDATE_INTERVAL_MS = 60000;
// Main template for this element
const template = (ele) => html`
<app-sk>
<header><h1>Power Controller</h1></header>
<main>
<h2>Broken Bots (with powercycle support)</h2>
${downBotsTable(ele._bots, ele._hosts)}
</main>
<footer>
<error-toast-sk></error-toast-sk>
</footer>
<app-sk>`;
const downBotsTable = (bots, hosts) => html`
<table>
<thead>
<tr>
<th>Name</th>
<th>Key Dimensions</th>
<th>Status</th>
<th>Since</th>
<th>Silenced</th>
</tr>
</thead>
<tbody>
${listBots(bots)}
</tbody>
</table>
<h2>Powercycle Commands</h2>
${listHosts(hosts, bots)}`;
const listBots = (bots) => bots.map(bot => {
return html`
<tr>
<td>${bot.bot_id}</td>
<td>${_keyDimension(bot)}</td>
<td>${bot.status}</td>
<td>${diffDate(bot.since)} ago</td>
<td>${bot.silenced}</td>
</tr>`
});
const listHosts = (hosts, bots) => hosts.map(host => {
return html`
<h3>On ${ host }</h3>
<div class=code>${_command(host, bots)}</div>`
});
// Helpers for templating
function _keyDimension(bot) {
// TODO(kjlubick): Make this show only the important dimension.
// e.g. for Android devices, just show "Nexus Player" or whatever
if (!bot || !bot.dimensions) {
return '';
}
let os = '';
bot.dimensions.forEach(function(d){
if (d.key === 'os') {
os = d.value[d.value.length - 1];
}
});
return os;
}
function _command(host, bots) {
let hasBots = false;
let cmd = 'powercycle --logtostderr ';
for (let bot of bots) {
if (bot.host_id === host && !bot.silenced) {
hasBots = true;
cmd += bot.bot_id;
if (bot.status.startsWith('Device')) {
cmd += '-device';
}
cmd += ' ';
}
};
if (!hasBots) {
return 'No unsilenced bots down :)'
}
return cmd;
}
// The <power-index-sk> custom element declaration.
//
// This is the main page for power.skia.org.
//
// Attributes:
// None
//
// Properties:
// None
//
// Events:
// None
//
// Methods:
// None
//
define('power-index-sk', class extends HTMLElement {
constructor() {
super();
this._hosts = [];
this._bots = [];
}
connectedCallback() {
this._render();
// make a fetch ASAP, but not immediately (demo mock up may not be set up yet)
window.setTimeout(() => this.update());
}
update() {
fetch('/down_bots')
.then(jsonOrThrow)
.then((json) => {
json.list = json.list || [];
let byHost = {};
json.list.forEach(function(b){
var host_arr = byHost[b.host_id] || [];
host_arr.push(b.bot_id);
byHost[b.host_id] = host_arr;
});
json.list.sort(function(a,b){
return a.bot_id.localeCompare(b.bot_id);
});
this._bots = json.list;
this._hosts = Object.keys(byHost);
this._render();
window.setTimeout(() => this.update(), UPDATE_INTERVAL_MS);
})
.catch((e) => {
errorMessage(e);
window.setTimeout(() => this.update(), UPDATE_INTERVAL_MS);
});
}
_render() {
render(template(this), this, {eventContext: this});
}
});