Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(678)

Unified Diff: appengine/swarming/elements/res/imp/botlist/bot-list.html

Issue 2408743002: Move elements/ to ui/ (Closed)
Patch Set: rebase again Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/swarming/elements/res/imp/botlist/bot-list.html
diff --git a/appengine/swarming/elements/res/imp/botlist/bot-list.html b/appengine/swarming/elements/res/imp/botlist/bot-list.html
deleted file mode 100644
index eb583e1c3d3e66a9655cd28daf12b72c509d6005..0000000000000000000000000000000000000000
--- a/appengine/swarming/elements/res/imp/botlist/bot-list.html
+++ /dev/null
@@ -1,644 +0,0 @@
-<!--
- Copyright 2016 The LUCI Authors. All rights reserved.
- Use of this source code is governed under the Apache License, Version 2.0
- that can be found in the LICENSE file.
-
- This in an HTML Import-able file that contains the definition
- of the following elements:
-
- <bot-list>
-
- bot-list creats a dynamic table for viewing swarming bots. Columns can be
- dynamically filtered and it supports client-side filtering.
-
- This is a top-level element.
-
- Properties:
- client_id: String, Oauth 2.0 client id. It will be set by server-side
- template evaluation.
-
- Methods:
- None.
-
- Events:
- None.
--->
-
-<link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="/res/imp/bower_components/polymer/polymer.html">
-
-<link rel="import" href="/res/imp/common/dynamic-table-behavior.html">
-<link rel="import" href="/res/imp/common/error-toast.html">
-<link rel="import" href="/res/imp/common/sort-toggle.html">
-<link rel="import" href="/res/imp/common/swarming-app.html">
-<link rel="import" href="/res/imp/common/url-param.html">
-<link rel="import" href="/res/imp/common/pageable-data.html">
-
-<link rel="import" href="bot-filters.html">
-<link rel="import" href="bot-list-data.html">
-<link rel="import" href="bot-list-shared-behavior.html">
-<link rel="import" href="bot-list-summary.html">
-
-<dom-module id="bot-list">
- <template>
- <style include="iron-flex iron-flex-alignment iron-positioning swarming-app-style dynamic-table-style">
- bot-filters, bot-list-summary {
- margin-bottom: 8px;
- margin-right: 10px;
- }
- .quarantined, .bad-device {
- background-color: #ffdddd;
- }
- .dead {
- background-color: #cccccc;
- }
- .bot-list th > span {
- /* Leave space for sort-toggle*/
- padding-right: 30px;
- }
- </style>
-
- <url-param name="s"
- value="{{_sortstr}}"
- default_value="id:asc">
- </url-param>
-
- <swarming-app
- client_id="[[client_id]]"
- auth_headers="{{_auth_headers}}"
- signed_in="{{_signed_in}}"
- server_details="{{_server_details}}"
-
- busy="[[_or(_busy1,_busy2)]]"
- name="Swarming Bot List">
-
- <h2 hidden$="[[_signed_in]]">You must sign in to see anything useful.</h2>
-
- <div hidden$="[[_not(_signed_in)]]">
-
- <div class="horizontal layout">
-
- <bot-filters
- dimensions="[[_dimensions]]"
- primary_map="[[_primary_map]]"
- primary_arr="[[_primary_arr]]"
-
- columns="{{_columns}}"
- query_params="{{_query_params}}"
- filter="{{_filter}}"
- verbose="{{_verbose}}">
- </bot-filters>
-
- <bot-list-summary
- columns="[[_columns]]"
- fleet="[[_fleet]]"
- filtered_bots="[[_filteredSortedItems]]"
- sort="[[_sortstr]]"
- verbose="[[_verbose]]">
- </bot-list-summary>
-
- </div>
-
- <bot-list-data
- id="data"
- auth_headers="[[_auth_headers]]"
- query_params="[[_query_params]]"
-
- busy="{{_busy1}}"
- dimensions="{{_dimensions}}"
- fleet="{{_fleet}}"
- primary_map="{{_primary_map}}"
- primary_arr="{{_primary_arr}}">
- </bot-list-data>
-
- <table class="bot-list">
- <thead on-sort_change="_sortChange">
- <!-- To allow for dynamic columns without having a lot of copy-pasted
- code, we break columns up into "special" and "plain" columns. Special
- columns require some sort of HTML output (e.g. anchor tags) and plain
- columns just output text. The plain columns use Polymer functions to
- insert their text [_header(), _column(), _deviceColumn()]. Polymer
- functions do not allow HTML (to avoid XSS), so special columns, like id
- and task are inserted in a fixed order.
- -->
- <tr>
- <th>
- <span>Bot Id</span>
- <sort-toggle
- name="id"
- current="[[_sort]]">
- </sort-toggle>
- </th>
- <!-- This wonky syntax is the proper way to listen to changes on an
- array (we are listening to all subproperties). The element returned is
- not of much use, so we'll ignore it in _hide() and use this._columns.
- -->
- <th hidden$="[[_hide('cloud_console_link', _columns.*)]]">
- <span>Bot in Cloud Console</span>
- <sort-toggle
- name="cloud_console_link"
- current="[[_sort]]">
- </sort-toggle>
- </th>
- <th hidden$="[[_hide('mp_lease_id', _columns.*)]]">
- <span>Machine Provider Lease Id</span>
- <sort-toggle
- name="mp_lease_id"
- current="[[_sort]]">
- </sort-toggle>
- </th>
- <th hidden$="[[_hide('task', _columns.*)]]">
- <span>Current Task</span>
- <sort-toggle
- name="task"
- current="[[_sort]]">
- </sort-toggle>
- </th>
-
- <template
- is="dom-repeat"
- items="[[_plainColumns]]"
- as="c">
- <th hidden$="[[_hide(c)]]">
- <span>[[_header(c)]]</span>
- <sort-toggle
- name="[[c]]"
- current="[[_sort]]">
- </sort-toggle>
- </th>
- </template>
- </tr>
- </thead>
- <tbody>
- <template
- id="bot_table"
- is="dom-repeat"
- items="[[_filteredSortedItems]]"
- as="bot"
- initial-count=50>
-
- <tr class$="[[_botClass(bot)]]">
- <td>
- <a
- class="center"
- href$="[[_botLink(bot.bot_id)]]"
- target="_blank"
- rel="noopener">
- [[bot.bot_id]]
- </a>
- </td>
- <td hidden$="[[_hide('cloud_console_link', _columns.*)]]">
- <a href$="[[_ccLink(bot)]]">[[_ccText(bot)]]</a>
- </td>
- <td hidden$="[[_hide('mp_lease_id', _columns.*)]]">
- <a href$="[[_mpLink(bot, _server_details.machine_provider_template)]]">
- [[_column('mp_lease_id', bot,_verbose)]]
- </a>
- </td>
- <td hidden$="[[_hide('task', _columns.*)]]">
- <a href$="[[_taskLink(bot.task_id)]]">[[_taskId(bot)]]</a>
- </td>
-
- <template
- is="dom-repeat"
- items="[[_plainColumns]]"
- as="c">
- <td hidden$="[[_hide(c)]]">
- [[_column(c, bot, _verbose)]]
- </td>
- </template>
-
- </tr>
- <template
- is="dom-repeat"
- items="[[_devices(bot)]]"
- as="device">
- <tr
- hidden$="[[_hide('android_devices', _columns.*)]]"
- class$="[[_deviceClass(device)]]">
- <td></td>
- <td hidden$="[[_hide('task', _columns.*)]]"></td>
- <template
- is="dom-repeat"
- items="[[_plainColumns]]"
- as="c">
- <td hidden$="[[_hide(c)]]">
- [[_deviceColumn(c, device, _verbose)]]
- </td>
- </template>
- </tr>
- </template> <!--devices repeat-->
- </template> <!--bot-table repeat-->
- </tbody>
- </table>
- <pageable-data
- id="page_bots"
- busy="{{_busy2}}"
- label="Show more bots"
- output="{{_items}}"
- parse="[[_parseBots]]">
- </pageable-data>
- </div>
-
- <error-toast></error-toast>
- </swarming-app>
-
- </template>
- <script>
- (function(){
- var UNKNOWN = "unknown";
- // see dynamic-table for more information on specialColumns, headerMap,
- // columnMap, and specialSort
- var specialColumns = ["id", "task", "cloud_console_link", "mp_lease_id"];
-
- var headerMap = {
- // "id" and "task" are special, so they don't go here. They have their
- // headers hard-coded above.
- "android_devices": "Android Devices",
- "battery_health": "Battery Health",
- "battery_level": "Battery Level (%)",
- "battery_status": "Battery Status",
- "battery_temperature": "Battery Temp (°C)",
- "battery_voltage": "Battery Voltage (mV)",
- "bot_temperature": "Bot Temp (°C)",
- "cores": "Cores",
- "cpu": "CPU",
- "device": "Non-android Device",
- "device_os": "Device OS",
- "device_temperature": "Device Temp (°C)",
- "device_type": "Device Type",
- "disk_space": "Free Space (MB)",
- "first_seen": "First Seen",
- "gpu": "GPU",
- "last_seen": "Last Seen",
- "mp_lease_expires": "Machine Provider Lease Expires",
- "os": "OS",
- "pool": "Pool",
- "running_time": "Swarming Uptime",
- "status": "Status",
- "uptime": "Bot Uptime",
- "xcode_version": "XCode Version",
- };
-
- var columnMap = {
- android_devices: function(bot) {
- var devs = this._attribute(bot, "android_devices", "0");
- if (this._verbose) {
- return devs.join(" | ") + " devices available";
- }
- // max() works on strings as long as they can be coerced to Number.
- return Math.max(...devs) + " devices available";
- },
- battery_health: function(){
- return "";
- },
- battery_level: function(){
- return "";
- },
- battery_status: function(){
- return "";
- },
- battery_temperature: function(){
- return "";
- },
- battery_voltage: function(){
- return "";
- },
- bot_temperature: function(bot){
- if (this._verbose) {
- return bot.state.temp.zones || UNKNOWN;
- }
- return bot.state.temp.average || UNKNOWN;
- },
- device_temperature: function(){
- return "";
- },
- disk_space: function(bot) {
- var aliased = [];
- bot.disks.forEach(function(disk){
- var alias = sk.human.bytes(disk.mb, sk.MB);
- aliased.push(swarming.alias.apply(disk.mb, disk.id + " "+ alias));
- }.bind(this));
- if (this._verbose) {
- return aliased.join(" | ");
- }
- return aliased[0];
- },
- external_ip: function(bot) {
- return bot.external_ip || "none";
- },
- first_seen: function(bot) {
- return sk.human.localeTime(bot.first_seen_ts)
- },
- id: function(bot) {
- return bot.bot_id;
- },
- last_seen: function(bot) {
- if (this._verbose) {
- return sk.human.localeTime(bot.last_seen_ts);
- }
- return this._timeDiffApprox(bot.last_seen_ts) + " ago";
- },
- mp_lease_id: function(bot) {
- var id = bot.lease_id || "none";
- if (this._verbose) {
- return id;
- }
- return id.substring(0, 10);
- },
- mp_lease_expires: function(bot) {
- if (!bot.lease_expiration_ts) {
- return "N/A";
- }
- if (this._verbose) {
- return sk.human.localeTime(bot.lease_expiration_ts);
- }
- if (bot.lease_expiration_ts < new Date()) {
- return this._timeDiffApprox(bot.lease_expiration_ts) + " ago";
- }
- return "in " + this._timeDiffApprox(bot.lease_expiration_ts);
- },
- running_time: function(bot) {
- var u = this._state(bot, "running_time");
- if (!u) {
- return "unknown";
- }
- return sk.human.strDuration(u);
- },
- status: function(bot) {
- // If a bot is both dead and quarantined, show the deadness over the
- // quarentinedness.
- if (bot.is_dead) {
- return "Dead. Last seen " + sk.human.diffDate(bot.last_seen_ts) +
- " ago";
- }
- if (bot.quarantined) {
- var msg = this._state(bot, "quarantined")[0];
- // Sometimes, the quarantined message is actually in "error". This
- // happens when the bot code has thrown an exception.
- if (msg === UNKNOWN || msg === "true" || msg === true) {
- msg = this._attribute(bot, "error");
- }
- return "Quarantined: " + msg;
- }
- return "Alive";
- },
- task: function(bot) {
- return this._taskId(bot);
- },
- uptime: function(bot) {
- var u = this._state(bot, "uptime");
- if (!u) {
- return "unknown";
- }
- return sk.human.strDuration(u);
- },
- version: function(bot) {
- var v = bot.version || UNKNOWN
- return v.substring(0, 10);
- }
- };
-
- var deviceColumnMap = {
- android_devices: function(device) {
- var str = this._androidAliasDevice(device);
- if (device.okay) {
- str = swarming.alias.apply(this._deviceType(device), str);
- }
- str += " S/N:";
- str += device.serial;
- return str;
- },
- battery_health: function(device){
- var h = (device.battery && device.battery.health) || UNKNOWN;
- return swarming.alias.apply(h, "battery_health");
- },
- battery_level: function(device){
- return (device.battery && device.battery.level) || UNKNOWN;
- },
- battery_status: function(device){
- var s = (device.battery && device.battery.status) || UNKNOWN;
- return swarming.alias.apply(s, "battery_status");
- },
- battery_temperature: function(device){
- // Battery temps are in tenths of degrees C - convert to more human range.
- return (device.battery && device.battery.temperature / 10) || UNKNOWN
- },
- battery_voltage: function(device){
- return (device.battery && device.battery.voltage) || UNKNOWN;
- },
- device_temperature: function(device){
- if (this._verbose) {
- return device.temp.zones || UNKNOWN;
- }
- return device.temp.average || UNKNOWN;
- },
- device_os: function(device) {
- if (device.build) {
- return device.build["build.id"];
- }
- return UNKNOWN;
- },
- status: function(device) {
- return device.state;
- }
- }
-
-
- function deviceAverage(col) {
- return function(dir, botA, botB) {
- // sort by average of all devices or 0 if no devices.
- var avgA = 0;
- var avgB = 0;
- var devsA = this._devices(botA);
- devsA.forEach(function(device) {
- var v = deviceColumnMap[col](device);
- v = parseFloat(swarming.alias.unapply(v)) || 0;
- avgA += v / devsA.length;
- }.bind(this));
- var devsB = this._devices(botB);
- devsB.forEach(function(device) {
- var v = deviceColumnMap[col](device);
- v = parseFloat(swarming.alias.unapply(v)) || 0;
- avgB += v / devsB.length;
- }.bind(this));
- return dir * swarming.naturalCompare(avgA, avgB);
- };
- }
-
- var specialSort = {
- android_devices: function(dir, botA, botB) {
- // We sort on the number of attached devices. Note that this
- // may not be the same as android_devices, because _devices().length
- // counts all devices plugged into the bot, whereas android_devices
- // counts just devices ready for work.
- var botACol = this._devices(botA).length;
- var botBCol = this._devices(botB).length;
- return dir * swarming.naturalCompare(botACol, botBCol);
- },
-
- battery_health: deviceAverage("battery_health"),
- battery_level: deviceAverage("battery_level"),
- battery_status: deviceAverage("battery_status"),
- battery_temperature: deviceAverage("battery_temperature"),
- battery_voltage: deviceAverage("battery_voltage"),
- device_temperature: deviceAverage("device_temperature"),
-
- bot_temperature: function(dir, botA, botB) {
- // Sort by average temperature.
- var botACol = botA.state.temp.average || 0;
- var botBCol = botB.state.temp.average || 0;
- return dir * swarming.naturalCompare(botACol, botBCol);
- },
- disk_space: function(dir, botA, botB) {
- // We sort based on the raw number of MB of the first disk.
- var botACol = botA.disks[0].mb;
- var botBCol = botB.disks[0].mb;
- return dir * swarming.naturalCompare(botACol, botBCol);
- },
- first_seen: function(dir, botA, botB) {
- var botACol = botA.first_seen_ts;
- var botBCol = botB.first_seen_ts;
- return dir * swarming.naturalCompare(botACol, botBCol)
- },
- last_seen: function(dir, botA, botB) {
- var botACol = botA.last_seen_ts;
- var botBCol = botB.last_seen_ts;
- return dir * swarming.naturalCompare(botACol, botBCol)
- },
- running_time: function(dir, botA, botB) {
- var botACol = this._state(botA, "running_time") || 0;
- var botBCol = this._state(botB, "running_time") || 0;
- return dir * swarming.naturalCompare(botACol, botBCol)
- },
- uptime: function(dir, botA, botB) {
- var botACol = this._state(botA, "uptime") || 0;
- var botBCol = this._state(botB, "uptime") || 0;
- return dir * swarming.naturalCompare(botACol, botBCol)
- },
- };
-
- Polymer({
- is: 'bot-list',
-
- // The order behaviors are applied in matters - later ones overwrite
- // attributes of earlier ones
- behaviors: [
- SwarmingBehaviors.BotListBehavior,
- SwarmingBehaviors.DynamicTableBehavior,
- ],
-
- properties: {
- client_id: {
- type: String,
- },
-
- _busy1: {
- type: Boolean,
- value: false
- },
- _busy2: {
- type: Boolean,
- value: false
- },
- _parseBots: {
- type: Function,
- value: function() {
- return this.$.data.parseBots.bind(this);
- }
- },
-
- // For dynamic table.
- _columnMap: {
- type: Object,
- value: function() {
- var base = this._commonColumns();
- for (var attr in columnMap) {
- base[attr] = columnMap[attr];
- }
- return base;
- },
- },
- _headerMap: {
- type: Object,
- value: headerMap,
- },
- _specialColumns: {
- type: Array,
- value: specialColumns,
- },
- _specialSort: {
- type: Object,
- value: specialSort,
- },
- },
-
- observers:["_reload(_query_params,_auth_headers)"],
-
- _androidAliasDevice: function(device) {
- if (device.notReady) {
- return UNAUTHENTICATED.toUpperCase();
- }
- return swarming.alias.android(this._deviceType(device));
- },
-
- _botClass: function(bot) {
- if (bot.is_dead) {
- return "dead";
- }
- if (bot.quarantined) {
- return "quarantined";
- }
- return "";
- },
-
- _ccLink: function(bot){
- var z = this._attribute(bot, "zone")[0];
- if (z === "unknown") {
- return undefined;
- }
- return this._cloudConsoleLink(z, bot.bot_id);
- },
-
- _ccText: function(bot){
- var z = this._attribute(bot, "zone")[0];
- if (z === "unknown") {
- return "Not on GCE";
- }
- return "View Bot";
- },
-
- _deviceColumn: function(col, device) {
- var f = deviceColumnMap[col];
- if (!f || !device) {
- return "";
- }
- return f.bind(this)(device);
- },
-
- _deviceClass: function(device) {
- if (!device.okay) {
- return "bad-device";
- }
- return "";
- },
-
- _mpLink: function(bot, template) {
- if (!bot || !bot.lease_id || !template) {
- return false;
- }
- return template.replace("%s", bot.lease_id);
- },
-
- _reload: function() {
- if (!this._auth_headers || !this._query_params) {
- return;
- }
- var url = "/_ah/api/swarming/v1/bots/list?" + sk.query.fromParamSet(this._query_params);
- this.$.page_bots.load(url,this._auth_headers);
- }
-
- });
- })();
- </script>
-</dom-module>

Powered by Google App Engine
This is Rietveld 408576698