blob: d713348cde8bfe2db3496a9cd3c491b2016f874d [file] [log] [blame]
/**
* @license
* Copyright 2021 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
import {css, html, LitElement} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {BinarySizeInfo} from './binary-size';
const MINUS_SIGN = '\u2212';
const EM_DASH = '\u2014';
const LEFT_PARENTHESIS = '\u0028';
const RIGHT_PARENTHESIS = '\u0029';
@customElement('binary-size-table')
export class BinarySizeTable extends LitElement {
@property()
binarySizeInfo: BinarySizeInfo;
@property()
showAllRows: boolean;
static override styles = css`
table {
border-collapse: collapse;
}
th {
padding: 0.2em 0.4em;
text-align: center;
}
td {
white-space: normal;
word-break: break-word;
padding: 0.2em 0.4em;
border-top: 1px solid var(--border-color);
}
td.size {
text-align: right;
}
td.surplus {
color: var(--positive-green-text-color);
}
td.deficit {
color: var(--negative-red-text-color);
}
a {
color: var(--link-color);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
gr-button {
padding: 0.6em 0.4em;
}
`;
override render() {
const rows = this.binarySizeInfo?.rows
?.filter(
row =>
row.trySize !== row.ciSize || row.budgetExceeded || this.showAllRows
)
.map(
row => html` <tr>
<td class="size" title="${row.ciSize} B">
<a href="${row.ciUrl}" target="blank"
>${humanByteSize(row.ciSize)}</a
>
</td>
<td class="size" title="${row.trySize} B">
<a href="${row.tryUrl}" target="blank"
>${humanByteSize(row.trySize)}</a
>
</td>
<td
class="${row.creepExceeded ? 'size, deficit' : 'size'}"
title="${row.trySize - row.ciSize} B"
>
${humanByteSizeDelta(row.ciSize, row.trySize)}
</td>
<td class="size">${percentSizeDelta(row.ciSize, row.trySize)}</td>
${this.binarySizeInfo?.showCreepBudgets
? html` <td class="size" title="${row.tryCreepBudget} B">
${humanByteSize(row.tryCreepBudget!)}
</td>`
: ''}
${this.binarySizeInfo?.showBudgets
? html` <td class="size" title="${row.tryBudget} B">
<a href="${row.ownerUrl}" target="blank"
>${humanByteSize(row.tryBudget!)}</a
>
</td>
<td class="size, ${row.budgetExceeded ? 'deficit' : 'surplus'}">
${humanByteSizeRemainingBudget(row.tryBudget!, row.trySize)}
</td>`
: ''}
<td>${row.binary}</td>
<td>${row.builder}</td>
</tr>`
);
return html`
<gr-button @tap=${() => (this.showAllRows = !this.showAllRows)}>
Show ${this.showAllRows ? 'Less' : 'All'}
</gr-button>
<table>
<tr>
<th>Size before</th>
<th>Size after</th>
<th colspan="2">Size delta</th>
${
this.binarySizeInfo?.showCreepBudgets
? html`<th>Creep budget</th>`
: ''
}
${
this.binarySizeInfo?.showBudgets
? html`<th colspan="2">Budget info</th>`
: ''
}
<th>File</th>
<th>Builder</td>
</tr>
${rows}
</table>
`;
}
constructor(binarySizeInfo: BinarySizeInfo) {
super();
this.binarySizeInfo = binarySizeInfo;
this.showAllRows = false;
}
}
/**
* Convert a positive number of bytes to a human-readable string.
*/
export function humanByteSize(bytes: number): string {
const units = ['B', 'KiB', 'MiB', 'GiB'];
const decPoints = [0, 2, 3, 4];
let unitIndex = 0;
while (Math.abs(bytes) >= 2048 && unitIndex < units.length - 1) {
bytes /= 1024;
unitIndex += 1;
}
return `${bytes.toFixed(decPoints[unitIndex])} ${units[unitIndex]}`;
}
/**
* Return a plus for positive numbers, a minus for negative numbers.
*/
export function signFor(number: number): string {
if (number > 0) {
return '+';
} else if (number < 0) {
return MINUS_SIGN;
} else {
return '';
}
}
/**
* Convert a difference between two numbers of bytes to a human-readable
* string, with plus or minus in front.
*/
export function humanByteSizeDelta(before: number, after: number): string {
const delta = after - before;
if (delta === 0) {
return EM_DASH;
}
return signFor(delta) + humanByteSize(Math.abs(delta));
}
/**
* Convert a difference between two numbers to a percentage with 4 decimal
* places, with plus or minus in front.
*/
export function percentSizeDelta(before: number, after: number): string {
const delta = ((after - before) / before) * 100;
if (delta === 0) {
return EM_DASH;
}
return signFor(delta) + Math.abs(delta).toFixed(4) + '%';
}
/**
* Convert a difference between a size and it's corresponding budget (in
* bytes) to a human readable string showing the space remaining or the
* deficit (in parenthesis).
*/
export function humanByteSizeRemainingBudget(
budget: number,
size: number
): string {
const delta = budget - size;
if (delta === 0) {
return EM_DASH;
}
if (delta > 0) {
return humanByteSize(Math.abs(delta));
} else {
// deficit denoted by parenthesis - e.g.: (VALUE)
return (
LEFT_PARENTHESIS + humanByteSize(Math.abs(delta)) + RIGHT_PARENTHESIS
);
}
}