e24deb89fe
- Handle empty script sources - Fix list-panel groups, order by count Bug: v8:10644 Change-Id: I03d3915f709d47429040b591c0271e951eca58e9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3289642 Commit-Queue: Camillo Bruni <cbruni@chromium.org> Auto-Submit: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Patrick Thier <pthier@chromium.org> Cr-Commit-Position: refs/heads/main@{#78165}
197 lines
5.6 KiB
JavaScript
197 lines
5.6 KiB
JavaScript
// Copyright 2020 the V8 project 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 {App} from '../index.mjs'
|
|
|
|
import {FocusEvent, ToolTipEvent} from './events.mjs';
|
|
import {groupBy, LazyTable} from './helper.mjs';
|
|
import {CollapsableElement, DOM} from './helper.mjs';
|
|
|
|
DOM.defineCustomElement('view/list-panel',
|
|
(templateText) =>
|
|
class ListPanel extends CollapsableElement {
|
|
_selectedLogEntries = [];
|
|
_displayedLogEntries = [];
|
|
_timeline;
|
|
|
|
_detailsClickHandler = this._handleDetailsClick.bind(this);
|
|
_logEntryClickHandler = this._handleLogEntryClick.bind(this);
|
|
_logEntryMouseOverHandler = this._logEntryMouseOverHandler.bind(this);
|
|
|
|
constructor() {
|
|
super(templateText);
|
|
this.groupKey.addEventListener('change', e => this.requestUpdate());
|
|
this.showAllRadio.onclick = _ => this._showEntries(this._timeline);
|
|
this.showTimerangeRadio.onclick = _ =>
|
|
this._showEntries(this._timeline.selectionOrSelf);
|
|
this.showSelectionRadio.onclick = _ =>
|
|
this._showEntries(this._selectedLogEntries);
|
|
}
|
|
|
|
static get observedAttributes() {
|
|
return ['title'];
|
|
}
|
|
|
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
if (name == 'title') {
|
|
this.$('#title').innerHTML = newValue;
|
|
}
|
|
}
|
|
|
|
set timeline(timeline) {
|
|
console.assert(timeline !== undefined, 'timeline undefined!');
|
|
this._timeline = timeline;
|
|
this.$('.panel').style.display = timeline.isEmpty() ? 'none' : 'inherit';
|
|
this._initGroupKeySelect();
|
|
}
|
|
|
|
set selectedLogEntries(entries) {
|
|
if (entries === this._timeline) {
|
|
this.showAllRadio.click();
|
|
} else if (entries === this._timeline.selection) {
|
|
this.showTimerangeRadio.click();
|
|
} else {
|
|
this._selectedLogEntries = entries;
|
|
this.showSelectionRadio.click();
|
|
}
|
|
}
|
|
|
|
get entryClass() {
|
|
return this._timeline.at(0)?.constructor;
|
|
}
|
|
|
|
get groupKey() {
|
|
return this.$('#group-key');
|
|
}
|
|
|
|
get table() {
|
|
return this.$('#table');
|
|
}
|
|
|
|
get showAllRadio() {
|
|
return this.$('#show-all');
|
|
}
|
|
|
|
get showTimerangeRadio() {
|
|
return this.$('#show-timerange');
|
|
}
|
|
|
|
get showSelectionRadio() {
|
|
return this.$('#show-selection');
|
|
}
|
|
|
|
get _propertyNames() {
|
|
return this.entryClass?.propertyNames ?? [];
|
|
}
|
|
|
|
_initGroupKeySelect() {
|
|
const select = this.groupKey;
|
|
select.options.length = 0;
|
|
for (const propertyName of this._propertyNames) {
|
|
const option = DOM.element('option');
|
|
option.text = propertyName;
|
|
select.add(option);
|
|
}
|
|
}
|
|
|
|
_showEntries(entries) {
|
|
this._displayedLogEntries = entries;
|
|
this.requestUpdate();
|
|
}
|
|
|
|
_update() {
|
|
if (this._timeline.isEmpty()) return;
|
|
DOM.removeAllChildren(this.table);
|
|
if (this._displayedLogEntries.length == 0) return;
|
|
const propertyName = this.groupKey.selectedOptions[0].text;
|
|
const groups =
|
|
groupBy(this._displayedLogEntries, each => each[propertyName], true);
|
|
this._render(groups, this.table);
|
|
}
|
|
|
|
createSubgroups(group) {
|
|
const map = new Map();
|
|
const tempGroups = [];
|
|
for (let propertyName of this._propertyNames) {
|
|
map.set(
|
|
propertyName,
|
|
groupBy(group.entries, each => each[propertyName], true));
|
|
}
|
|
return map;
|
|
}
|
|
|
|
_handleLogEntryClick(e) {
|
|
const group = e.currentTarget.group;
|
|
this.dispatchEvent(new FocusEvent(group.key));
|
|
}
|
|
|
|
_logEntryMouseOverHandler(e) {
|
|
const group = e.currentTarget.group;
|
|
this.dispatchEvent(new ToolTipEvent(group.key, e.currentTarget));
|
|
}
|
|
|
|
_handleDetailsClick(event) {
|
|
event.stopPropagation();
|
|
const tr = event.target.parentNode;
|
|
const group = tr.group;
|
|
// Create subgroup in-place if the don't exist yet.
|
|
if (tr.groups === undefined) {
|
|
const groups = tr.groups = this.createSubgroups(group);
|
|
this.renderDrilldown(groups, tr);
|
|
}
|
|
const detailsTr = tr.nextSibling;
|
|
if (tr.classList.contains('open')) {
|
|
tr.classList.remove('open');
|
|
detailsTr.style.display = 'none';
|
|
} else {
|
|
tr.classList.add('open');
|
|
detailsTr.style.display = 'table-row';
|
|
}
|
|
}
|
|
|
|
renderDrilldown(groups, previousSibling) {
|
|
const tr = DOM.tr('entry-details');
|
|
tr.style.display = 'none';
|
|
// indent by one td.
|
|
tr.appendChild(DOM.td());
|
|
const td = DOM.td();
|
|
td.colSpan = 3;
|
|
groups.forEach((group, key) => {
|
|
this.renderDrilldownGroup(td, group, key);
|
|
});
|
|
tr.appendChild(td);
|
|
// Append the new TR after previousSibling.
|
|
previousSibling.parentNode.insertBefore(tr, previousSibling.nextSibling);
|
|
}
|
|
|
|
renderDrilldownGroup(td, groups, key) {
|
|
const div = DOM.div('drilldown-group-title');
|
|
div.textContent = `Grouped by ${key}: ${groups[0]?.parentTotal ?? 0}#`;
|
|
td.appendChild(div);
|
|
const table = DOM.table();
|
|
this._render(groups, table, false)
|
|
td.appendChild(table);
|
|
}
|
|
|
|
_render(groups, table) {
|
|
let last;
|
|
new LazyTable(table, groups, group => {
|
|
last = group;
|
|
const tr = DOM.tr();
|
|
tr.group = group;
|
|
const details = tr.appendChild(DOM.td('', 'toggle'));
|
|
details.onclick = this._detailsClickHandler;
|
|
tr.appendChild(DOM.td(`${group.percent.toFixed(2)}%`, 'percentage'));
|
|
tr.appendChild(DOM.td(group.length, 'count'));
|
|
const valueTd = tr.appendChild(DOM.td(group.key?.toString(), 'key'));
|
|
if (App.isClickable(group.key)) {
|
|
tr.onclick = this._logEntryClickHandler;
|
|
tr.onmouseover = this._logEntryMouseOverHandler;
|
|
valueTd.classList.add('clickable');
|
|
}
|
|
return tr;
|
|
}, 10);
|
|
}
|
|
});
|