blob: afd1a7b13bf7f25ead899a2d97473dd53d8d8b0e [file] [log] [blame]
/**
* @module module/perf-scaffold-sk
* @description <h2><code>perf-scaffold-sk</code></h2>
*
* Contains the title bar and error-toast for all the Perf pages. The rest of
* every Perf page should be a child of this element.
*
*/
import { html } from 'lit/html.js';
import { choose } from 'lit/directives/choose.js';
import { define } from '../../../elements-sk/modules/define';
import { ElementSk } from '../../../infra-sk/modules/ElementSk';
import '../../../elements-sk/modules/error-toast-sk';
import '../../../elements-sk/modules/icons/add-alert-icon-sk';
import '../../../elements-sk/modules/icons/build-icon-sk';
import '../../../elements-sk/modules/icons/bug-report-icon-sk';
import '../../../elements-sk/modules/icons/event-icon-sk';
import '../../../elements-sk/modules/icons/favorite-icon-sk';
import '../../../elements-sk/modules/icons/folder-icon-sk';
import '../../../elements-sk/modules/icons/help-icon-sk';
import '../../../elements-sk/modules/icons/home-icon-sk';
import '../../../elements-sk/modules/icons/multiline-chart-icon-sk';
import '../../../elements-sk/modules/icons/sort-icon-sk';
import '../../../elements-sk/modules/icons/trending-up-icon-sk';
import '../../../infra-sk/modules/alogin-sk';
import '../../../infra-sk/modules/theme-chooser-sk';
import '../../../infra-sk/modules/app-sk';
import { getBuildTag } from '../window/window';
// The ID of a top level element under perf-scaffold-sk that will be moved under
// the right hand side nav bar.
const SIDEBAR_HELP_ID = 'sidebar_help';
const BUILDBOT_GIT = 'https://skia.googlesource.com/buildbot.git/+log/';
/**
* Moves the elements from a list to be the children of the target element.
*
* @param from - The list of elements we are moving.
* @param to - The new parent.
*/
function move(from: HTMLCollection | NodeList, to: HTMLElement) {
Array.prototype.slice.call(from).forEach((ele) => to.appendChild(ele));
}
export class PerfScaffoldSk extends ElementSk {
private _main: HTMLElement | null = null;
private _help: HTMLElement | null = null;
private _chat: HTMLElement | null = null;
private _helpUrl: string = 'http://go/perf-user-doc';
private _reportBugUrl: string =
'https://issuetracker.google.com/issues/new?component=1547614&template=1970127';
private isHiddenTriage =
window.perf.show_triage_link !== null ? window.perf.show_triage_link : true;
constructor() {
super(PerfScaffoldSk.template);
}
private static template = (ele: PerfScaffoldSk) => html`
<app-sk>
<header id=topbar>
<h1 class=name>${ele.instanceTitleTemplate()}</h1>
<div class=spacer></div>
<alogin-sk url=/_/login/status></alogin-sk>
<theme-chooser-sk></theme-chooser-sk>
</header>
<aside id=sidebar>
<div id=links>
<a href="/e/" tab-index=0 ><home-icon-sk></home-icon-sk><span>New Query</span></a>
<a href="/f/" tab-index=0 ><favorite-icon-sk></favorite-icon-sk><span>Favorites</span></a>
<a href="/m/" tab-index=0 >
<multiline-chart-icon-sk></multiline-chart-icon-sk><span>MultiGraph</span>
</a>
<div class="triage-link" ?hidden=${!ele.isHiddenTriage}>
<a href="/t/" tab-index=0 ><trending-up-icon-sk></trending-up-icon-sk><span>Triage</span></a>
</div>
<a href="/a/" tab-index=0 ><add-alert-icon-sk></add-alert-icon-sk><span>Alerts</span></a>
<a href="/d/" tab-index=0 ><build-icon-sk></build-icon-sk><span>Dry Run</span></a>
<a href="/c/" tab-index=0 ><sort-icon-sk></sort-icon-sk><span>Clustering</span></a>
${this.revisionLinkTemplate()}
<a href="${ele._helpUrl}" target="_blank" tab-index=0 >
<help-icon-sk></help-icon-sk><span>Help</span>
</a>
<a href="${ele._reportBugUrl}" target="_blank" tab-index=0 >
<bug-report-icon-sk></bug-report-icon-sk><span>Report Bug</span>
</a>
${ele.buildTagTemplate()}
</div>
<div id=help>
</div>
<div id=chat>
</div>
</aside>
<main>
</main>
<footer class="glue-footer">
<error-toast-sk></error-toast-sk>
</footer>
</app-sk>
`;
private static revisionLinkTemplate = () => {
if (window.perf.fetch_chrome_perf_anomalies) {
return html`<a href="/v/" tab-index="0"
><trending-up-icon-sk></trending-up-icon-sk><span>Revision Info</span></a
>`;
}
return html``;
};
private buildTagLinkTemplate(tag: string) {
return html`<a href="${BUILDBOT_GIT}${tag}" target="_blank">Build: ${tag}</a>`;
}
private buildTagTemplate() {
const buildTag = getBuildTag();
return html`${choose(
buildTag.type,
[
['git', () => this.buildTagLinkTemplate(buildTag.tag!)],
['louhi', () => this.buildTagLinkTemplate(buildTag.tag!)],
['tag', () => html`<a>Build: ${buildTag.tag}</a>`],
],
() => html`<a>Build: No Tag</a>`
)}`;
}
private instanceTitleTemplate() {
if (window.perf.instance_url) {
return html`<a>${this.extractInstanceNameFromUrl(window.perf.instance_url)}</a>`;
}
}
// Extract the string between "https://" and the first "." in a URL,
// such as "https://androidx2-perf.luci.app"
private extractInstanceNameFromUrl(url: string): string {
const regex = /^https:\/\/(.*?)\./;
const match = url.match(regex);
// If a match is found, the captured group (the part between https:// and .)
// will be at index 1 of the match array.
if (match && match[1]) {
return match[1].at(0)!.toUpperCase() + match[1].substring(1);
}
return '';
}
connectedCallback(): void {
super.connectedCallback();
// Don't call more than once.
if (this._main) {
return;
}
// We aren't using shadow dom so we need to manually move the children of
// perf-scaffold-sk to be children of 'main'. We have to do this for the
// existing elements and for all future mutations.
// Create a temporary holding spot for elements we're moving.
const div = document.createElement('div');
move(this.children, div);
// Override the help url if specified in the instance config
if (window.perf.help_url_override && window.perf.help_url_override !== '') {
this._helpUrl = window.perf.help_url_override;
}
// Override the feedback / report bug url if specified in the instance config
if (window.perf.feedback_url && window.perf.feedback_url !== '') {
this._reportBugUrl = window.perf.feedback_url;
}
// Now that we've moved all the old children out of the way we can render
// the template.
this._render();
this._main = this.querySelector('main');
this._help = this.querySelector('#help');
this._chat = this.querySelector('#chat');
if (this._chat !== null) {
this.addUrlToElement(this._chat, 'Ask the team', window.perf.chat_url);
}
// Move the old children back.
this.redistributeAddedNodes(div.childNodes);
// Move all future children also.
const observer = new MutationObserver((mutList) => {
mutList.forEach((mut) => {
this.redistributeAddedNodes(mut.addedNodes);
});
});
observer.observe(this, { childList: true });
}
// addUrlToElement adds the provided url data inside the given html element.
private addUrlToElement(element: HTMLElement, urlText: string, urlHref: string) {
element.hidden = true;
if (urlHref && urlHref !== '') {
element.innerHTML = `<a target="_blank" href="${urlHref}"
tab-index=0><h4>${urlText}</h4></a>`;
element.hidden = false;
}
}
// Place these newly added nodes in the right place under the perf-scaffold-sk
// element.
private redistributeAddedNodes(from: NodeList) {
Array.prototype.slice.call(from).forEach((node: Node) => {
if ((node as Element).id === SIDEBAR_HELP_ID) {
this._help!.appendChild(node);
} else {
this._main!.appendChild(node);
}
});
}
}
define('perf-scaffold-sk', PerfScaffoldSk);