[tools][system-analyzer] Unify CustomEvents
This CL unifies the custom events by creating classes specialised based on the event type. Multiple entry selection causes panels to emit 'showentries' event. Single entry selection causes panels to emit 'showentrydetail' event. The events are received by the controller App class and updates the view of the panels and state of the app. Bug: v8:10644 Change-Id: Ibe26223459ba605c6d6d3f0025bf3a556dfb0578 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2335188 Commit-Queue: Zeynep Cankara <zcankara@google.com> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#69286}
This commit is contained in:
parent
b400c9b705
commit
393e434479
23
tools/system-analyzer/events.mjs
Normal file
23
tools/system-analyzer/events.mjs
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
// 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.
|
||||
|
||||
class SelectionEvent extends CustomEvent {
|
||||
constructor(entries){
|
||||
super('showentries', {bubbles: true, composed: true});
|
||||
if(!Array.isArray(entries) || entries.length == 0){
|
||||
throw new Error('No valid entries selected!')
|
||||
}
|
||||
this.entries = entries;
|
||||
}
|
||||
}
|
||||
|
||||
class SelectEvent extends CustomEvent {
|
||||
constructor(entry){
|
||||
super('showentrydetail', {bubbles: true, composed: true});
|
||||
this.entry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
export {SelectionEvent, SelectEvent};
|
@ -4,6 +4,7 @@
|
||||
|
||||
import {Group} from './ic-model.mjs';
|
||||
import CustomIcProcessor from "./ic-processor.mjs";
|
||||
import {SelectEvent} from './events.mjs';
|
||||
import {defineCustomElement, V8CustomElement} from './helper.mjs';
|
||||
|
||||
defineCustomElement('ic-panel', (templateText) =>
|
||||
@ -92,14 +93,11 @@ defineCustomElement('ic-panel', (templateText) =>
|
||||
}
|
||||
|
||||
handleMapClick(e){
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'mapclick', {bubbles: true, composed: true,
|
||||
detail: e.target.parentNode.entry}));
|
||||
this.dispatchEvent(new SelectEvent(e.target.parentNode.entry));
|
||||
}
|
||||
|
||||
handleFilePositionClick(e){
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'filepositionclick', {bubbles: true, composed: true,
|
||||
detail: e.target.parentNode.entry}));
|
||||
this.dispatchEvent(new SelectEvent(e.target.parentNode.entry.key));
|
||||
}
|
||||
|
||||
render(entries, parent) {
|
||||
|
@ -208,7 +208,7 @@ class CustomIcProcessor extends IcProcessor {
|
||||
return this.timeline;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(zcankara) Change name to Entry -> V8IcEntry or V8Ic
|
||||
class Entry extends Event {
|
||||
constructor(
|
||||
type, fn_file, time, line, column, key, oldState, newState, map, reason,
|
||||
@ -262,4 +262,4 @@ class Entry extends Event {
|
||||
}
|
||||
}
|
||||
|
||||
export { CustomIcProcessor as default };
|
||||
export { CustomIcProcessor as default, Entry};
|
||||
|
@ -3,9 +3,9 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import CustomIcProcessor from "./ic-processor.mjs";
|
||||
import {Entry} from "./ic-processor.mjs";
|
||||
import {State} from './app-model.mjs';
|
||||
import {MapProcessor, V8Map} from './map-processor.mjs';
|
||||
import {Chunk} from './timeline.mjs';
|
||||
import {$} from './helper.mjs';
|
||||
import './ic-panel.mjs';
|
||||
import './timeline-panel.mjs';
|
||||
@ -25,64 +25,54 @@ class App {
|
||||
icTrack: $(icTrackId),
|
||||
}
|
||||
this.#state = new State();
|
||||
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
|
||||
this.toggleSwitch.addEventListener('change', e => this.switchTheme(e));
|
||||
this.#view.logFileReader.addEventListener('fileuploadstart',
|
||||
e => this.handleFileUpload(e));
|
||||
this.#view.logFileReader.addEventListener('fileuploadend',
|
||||
e => this.handleDataUpload(e));
|
||||
this.toggleSwitch = $('.theme-switch input[type="checkbox"]');
|
||||
this.toggleSwitch.addEventListener('change', e => this.switchTheme(e));
|
||||
this.#view.timelinePanel.addEventListener(
|
||||
'mapchange', e => this.handleMapChange(e));
|
||||
this.#view.timelinePanel.addEventListener(
|
||||
'showmaps', e => this.handleShowMaps(e));
|
||||
this.#view.mapPanel.addEventListener(
|
||||
'mapchange', e => this.handleMapChange(e));
|
||||
this.#view.mapPanel.addEventListener(
|
||||
'selectmapdblclick', e => this.handleDblClickSelectMap(e));
|
||||
this.#view.mapPanel.addEventListener(
|
||||
'sourcepositionsclick', e => this.handleClickSourcePositions(e));
|
||||
Object.entries(this.#view).forEach(([_, value]) => {
|
||||
value.addEventListener('showentries',
|
||||
e => this.handleShowEntries(e));
|
||||
value.addEventListener('showentrydetail',
|
||||
e => this.handleShowEntryDetail(e));
|
||||
});
|
||||
this.#view.icPanel.addEventListener(
|
||||
'ictimefilter', e => this.handleICTimeFilter(e));
|
||||
this.#view.icPanel.addEventListener(
|
||||
'mapclick', e => this.handleMapClick(e));
|
||||
this.#view.mapPanel.addEventListener(
|
||||
'click', e => this.handleMapAddressSearch(e));
|
||||
this.#view.mapPanel.addEventListener(
|
||||
'change', e => this.handleShowMapsChange(e));
|
||||
this.#view.icPanel.addEventListener(
|
||||
'filepositionclick', e => this.handleFilePositionClick(e));
|
||||
}
|
||||
handleMapClick(e) {
|
||||
//TODO(zcankara) Direct the event based on the key and value
|
||||
console.log("map: ", e.detail.key);
|
||||
handleShowEntries(e){
|
||||
if(e.entries[0] instanceof V8Map){
|
||||
this.#view.mapPanel.mapEntries = e.entries;
|
||||
}
|
||||
}
|
||||
handleFilePositionClick(e) {
|
||||
//TODO(zcankara) Direct the event based on the key and value
|
||||
console.log("filePosition: ", e.detail.key);
|
||||
handleShowEntryDetail(e){
|
||||
if(e.entry instanceof V8Map){
|
||||
this.selectMapLogEvent(e.entry);
|
||||
}
|
||||
else if(e.entry instanceof Entry){
|
||||
this.selectICLogEvent(e.entry);
|
||||
}
|
||||
else if(typeof e.entry === 'string'){
|
||||
this.selectSourcePositionEvent(e.entry);
|
||||
}
|
||||
else {
|
||||
console.log("undefined");
|
||||
}
|
||||
}
|
||||
handleClickSourcePositions(e){
|
||||
//TODO(zcankara) Handle source position
|
||||
console.log("source position map detail: ", e.detail);
|
||||
console.log("Entry containing source position: ", e.entries);
|
||||
}
|
||||
handleDblClickSelectMap(e){
|
||||
//TODO(zcankara) Handle double clicked map
|
||||
console.log("double clicked map: ", e.detail);
|
||||
selectMapLogEvent(entry){
|
||||
this.#state.map = entry;
|
||||
this.#view.mapTrack.selectedEntry = entry;
|
||||
this.#view.mapPanel.map = entry;
|
||||
}
|
||||
handleMapChange(e){
|
||||
if (!(e.detail instanceof V8Map)){
|
||||
console.error("selected entry not a V8Map instance");
|
||||
return;
|
||||
}
|
||||
this.#state.map = e.detail;
|
||||
this.#view.mapTrack.selectedEntry = e.detail;
|
||||
this.#view.mapPanel.map = e.detail;
|
||||
selectICLogEvent(entry){
|
||||
console.log("IC Entry selection");
|
||||
}
|
||||
handleShowMaps(e){
|
||||
if (!(e.detail instanceof Chunk)){
|
||||
console.error("Chunk not selected");
|
||||
return;
|
||||
}
|
||||
this.#view.mapPanel.mapEntries = e.detail.filter();
|
||||
selectSourcePositionEvent(sourcePositions){
|
||||
console.log("source positions: ", sourcePositions);
|
||||
}
|
||||
handleICTimeFilter(event) {
|
||||
this.#state.timeSelection.start = event.detail.startTime;
|
||||
@ -91,29 +81,15 @@ class App {
|
||||
this.#state.timeSelection.end);
|
||||
this.#view.icPanel.filteredEntries = this.#view.icTrack.data.selection;
|
||||
}
|
||||
handleMapAddressSearch(e) {
|
||||
//TODO(zcankara) Combine with handleMapChange into selectMap event
|
||||
//TODO(zcankara) Possibility of select no map
|
||||
if(!e.detail.map) return;
|
||||
this.#state.map = e.detail.map;
|
||||
this.#view.mapTrack.selectedEntry = e.detail.map;
|
||||
this.#view.mapPanel.map = e.detail.map;
|
||||
}
|
||||
handleShowMapsChange(e) {
|
||||
//TODO(zcankara) Map entries repeats "map". Probabluy not needed
|
||||
this.#view.mapPanel.mapEntries = e.detail;
|
||||
}
|
||||
handleFileUpload(e){
|
||||
//TODO(zcankara) Set a state on the document.body. Exe: .loading, .loaded
|
||||
$('#container').style.display = 'none';
|
||||
}
|
||||
|
||||
// Map event log processing
|
||||
handleLoadTextMapProcessor(text) {
|
||||
let mapProcessor = new MapProcessor();
|
||||
return mapProcessor.processString(text);
|
||||
}
|
||||
|
||||
// IC event file reading and log processing
|
||||
loadICLogFile(fileData) {
|
||||
let reader = new FileReader();
|
||||
|
@ -4,6 +4,7 @@
|
||||
import "./stats-panel.mjs";
|
||||
import "./map-panel/map-details.mjs";
|
||||
import "./map-panel/map-transitions.mjs";
|
||||
import {SelectEvent} from './events.mjs';
|
||||
import {V8Map} from "./map-processor.mjs";
|
||||
import {defineCustomElement, V8CustomElement} from './helper.mjs';
|
||||
|
||||
@ -68,21 +69,16 @@ defineCustomElement('map-panel', (templateText) =>
|
||||
}
|
||||
|
||||
handleSearchBar(e){
|
||||
let dataModel = Object.create(null);
|
||||
let searchBar = this.$('#searchBarInput');
|
||||
let searchBarInput = searchBar.value;
|
||||
//access the map from model cache
|
||||
let selectedMap = V8Map.get(searchBarInput);
|
||||
if(selectedMap){
|
||||
dataModel.isValidMap = true;
|
||||
dataModel.map = selectedMap;
|
||||
searchBar.className = "success";
|
||||
} else {
|
||||
dataModel.isValidMap = false;
|
||||
searchBar.className = "failure";
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'click', {bubbles: true, composed: true, detail: dataModel}));
|
||||
this.dispatchEvent(new SelectEvent(selectedMap));
|
||||
}
|
||||
|
||||
set mapEntries(list){
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
import {V8CustomElement, defineCustomElement} from '../helper.mjs';
|
||||
import {SelectEvent} from '../events.mjs';
|
||||
|
||||
defineCustomElement('./map-panel/map-details', (templateText) =>
|
||||
class MapDetails extends V8CustomElement {
|
||||
@ -30,8 +31,6 @@ defineCustomElement('./map-panel/map-details', (templateText) =>
|
||||
}
|
||||
|
||||
handleClickSourcePositions(){
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'sourcepositionsclick', {bubbles: true, composed: true, detail: this.selectedMap.filePosition}));
|
||||
this.dispatchEvent(new SelectEvent(this.selectedMap.filePosition));
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
import {V8CustomElement, defineCustomElement} from '../helper.mjs';
|
||||
import {SelectEvent} from '../events.mjs';
|
||||
|
||||
defineCustomElement('./map-panel/map-transitions', (templateText) =>
|
||||
class MapTransitions extends V8CustomElement {
|
||||
@ -45,13 +46,11 @@ defineCustomElement('./map-panel/map-transitions', (templateText) =>
|
||||
this.currentMap = map;
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'mapdetailsupdate', {bubbles: true, composed: true, detail: map}));
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'mapchange', {bubbles: true, composed: true, detail: map}));
|
||||
this.dispatchEvent(new SelectEvent(map));
|
||||
}
|
||||
|
||||
dblClickSelectMap(map) {
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'selectmapdblclick', {bubbles: true, composed: true, detail: map}));
|
||||
this.dispatchEvent(new SelectEvent(map));
|
||||
}
|
||||
|
||||
showMap() {
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
import {V8CustomElement, defineCustomElement} from './helper.mjs';
|
||||
import {SelectionEvent} from './events.mjs';
|
||||
|
||||
defineCustomElement('stats-panel', (templateText) =>
|
||||
class StatsPanel extends V8CustomElement {
|
||||
@ -88,8 +89,7 @@ defineCustomElement('stats-panel', (templateText) =>
|
||||
if (node.maps == undefined) {
|
||||
node.maps = this.filterUniqueTransitions(filter);
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'change', {bubbles: true, composed: true, detail: node.maps}));
|
||||
this.dispatchEvent(new SelectionEvent(node.maps));
|
||||
};
|
||||
row.appendChild(this.td(name));
|
||||
let count = this.timeline.count(filter);
|
||||
@ -113,9 +113,8 @@ defineCustomElement('stats-panel', (templateText) =>
|
||||
row.maps = maps;
|
||||
row.addEventListener(
|
||||
'click',
|
||||
e => this.dispatchEvent(new CustomEvent(
|
||||
'change', {bubbles: true, composed: true,
|
||||
detail: e.target.parentNode.maps.map(map => map.to)})));
|
||||
e => this.dispatchEvent(
|
||||
new SelectionEvent(e.target.parentNode.maps.map(map => map.to))));
|
||||
row.appendChild(this.td(name));
|
||||
row.appendChild(this.td(maps.length));
|
||||
tableNode.appendChild(row);
|
||||
|
@ -5,6 +5,7 @@
|
||||
import {defineCustomElement, V8CustomElement,
|
||||
transitionTypeToColor, CSSColor} from '../helper.mjs';
|
||||
import {kChunkWidth, kChunkHeight} from '../map-processor.mjs';
|
||||
import {SelectionEvent, SelectEvent} from '../events.mjs';
|
||||
|
||||
defineCustomElement('./timeline/timeline-track', (templateText) =>
|
||||
class TimelineTrack extends V8CustomElement {
|
||||
@ -107,12 +108,7 @@ defineCustomElement('./timeline/timeline-track', (templateText) =>
|
||||
}
|
||||
|
||||
handleEntryTypeDblClick(e){
|
||||
let selectedEvent = {
|
||||
entries: e.target.entries
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'selectionevent', {bubbles: true, composed: true,
|
||||
detail: selectedEvent}));
|
||||
this.dispatchEvent(new SelectionEvent(e.target.entries));
|
||||
}
|
||||
|
||||
timelineIndicatorMove(offset) {
|
||||
@ -230,8 +226,7 @@ defineCustomElement('./timeline/timeline-track', (templateText) =>
|
||||
let relativeIndex =
|
||||
Math.round(event.layerY / event.target.offsetHeight * chunk.size());
|
||||
let map = chunk.at(relativeIndex);
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'mapchange', {bubbles: true, composed: true, detail: map}));
|
||||
this.dispatchEvent(new SelectEvent(map));
|
||||
}
|
||||
|
||||
handleChunkClick(event) {
|
||||
@ -242,8 +237,8 @@ defineCustomElement('./timeline/timeline-track', (templateText) =>
|
||||
this.isLocked = true;
|
||||
let chunk = event.target.chunk;
|
||||
if (!chunk) return;
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
'showmaps', {bubbles: true, composed: true, detail: chunk}));
|
||||
let maps = chunk.filter();
|
||||
this.dispatchEvent(new SelectionEvent(maps));
|
||||
}
|
||||
|
||||
drawOverview() {
|
||||
|
Loading…
Reference in New Issue
Block a user