1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; 17import {LitTabs} from "../../../../base-ui/tabs/lit-tabs.js"; 18import {CpuStruct} from "../../../bean/CpuStruct.js"; 19import {LitTabpane} from "../../../../base-ui/tabs/lit-tabpane.js"; 20import {BoxJumpParam, SelectionParam} from "../../../bean/BoxSelection.js"; 21import {TabPaneCurrentSelection} from "../sheet/TabPaneCurrentSelection.js"; 22import {FuncStruct} from "../../../bean/FuncStruct.js"; 23import {ProcessMemStruct} from "../../../bean/ProcessMemStruct.js"; 24import {ThreadStruct} from "../../../bean/ThreadStruct.js"; 25import {TabPaneFlag} from "../timer-shaft/TabPaneFlag.js"; 26import {Flag} from "../timer-shaft/Flag.js"; 27import {WakeupBean} from "../../../bean/WakeupBean.js"; 28import {LitIcon} from "../../../../base-ui/icon/LitIcon.js"; 29import {CpuFreqStruct} from "../../../bean/CpuFreqStruct.js"; 30import {tabConfig} from "./TraceSheetConfig.js"; 31import {TabPaneBoxChild} from "../sheet/cpu/TabPaneBoxChild.js"; 32import {CpuStateStruct} from "../../../database/ui-worker/ProcedureWorkerCpuState.js"; 33import {SpFreqChart} from "../../chart/SpFreqChart.js"; 34import {CpuFreqLimitsStruct} from "../../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js"; 35 36 37@element("trace-sheet") 38export class TraceSheet extends BaseElement { 39 private litTabs: LitTabs | undefined | null 40 private nav: HTMLDivElement | undefined | null 41 private selection: SelectionParam | undefined | null; 42 private currentPaneID: string = "current-selection"; 43 44 static get observedAttributes() { 45 return ['mode']; 46 } 47 48 buildTabs(litTabs: LitTabs | undefined | null) { 49 Reflect.ownKeys(tabConfig).forEach((key, index) => { 50 let pane = new LitTabpane(); 51 pane.id = key.toString(); 52 pane.className = "tabHeight"; 53 pane.tab = tabConfig[key].title; 54 pane.hidden = true; 55 pane.key = `${tabConfig[key].key || index}`; 56 let cls = tabConfig[key].type; 57 let node = new cls(); 58 pane.append(node) 59 litTabs!.append(pane); 60 }) 61 } 62 63 displayTab<T>(...names: string[]): T { 64 this.setAttribute("mode", "max") 65 this.shadowRoot?.querySelectorAll<LitTabpane>("#tabs lit-tabpane").forEach(it => it.hidden = !names.some(k => k === it.id)) 66 let litTabpane = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[id='${names[0]}']`); 67 this.shadowRoot?.querySelector<LitTabs>("#tabs")?.activePane(litTabpane!.key) 68 return litTabpane!.children.item(0) as unknown as T; 69 } 70 71 getComponentByID<T>(id: string): T { 72 return (this.getPaneByID(id)!.children.item(0) as unknown as T); 73 } 74 75 getPaneByID(id: string): LitTabpane { 76 return this.shadowRoot!.querySelector(`#${id}`)!; 77 } 78 79 initElements(): void { 80 this.litTabs = this.shadowRoot?.querySelector("#tabs"); 81 this.buildTabs(this.litTabs); 82 let minBtn = this.shadowRoot?.querySelector("#min-btn"); 83 minBtn?.addEventListener('click', () => { 84 }); 85 this.litTabs!.onTabClick = (e: any) => this.loadTabPaneData(e.detail.key) 86 this.litTabs!.addEventListener("close-handler", () => { 87 Reflect.ownKeys(tabConfig).reverse().forEach(id => { 88 let element = tabConfig[id]; 89 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 90 if (element.require) { 91 pane!.hidden = !element.require(this.selection); 92 } else { 93 pane!.hidden = true; 94 } 95 }) 96 this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`); 97 }) 98 this.getComponentByID<any>("box-spt")!.addEventListener("row-click", this.rowClickHandler.bind(this)); 99 this.getComponentByID<any>("box-pts")!.addEventListener("row-click", this.rowClickHandler.bind(this)); 100 this.getComponentByID<any>("box-cs")!.addEventListener("row-click", this.rowClickHandler.bind(this)); 101 this.getComponentByID<any>("box-ts")!.addEventListener("row-click", this.rowClickHandler.bind(this)); 102 this.getComponentByID<any>("box-native-statstics")!.addEventListener("row-click", (e: any) => { 103 this.selection!.statisticsSelectData = e.detail 104 let pane = this.getPaneByID("box-native-memory"); 105 this.litTabs?.activeByKey(pane.key); 106 (pane.children.item(0) as any)!.fromStastics(this.selection) 107 }); 108 this.getComponentByID<any>("box-virtual-memory-statistics")!.addEventListener("row-click", (e: any) => { 109 this.selection!.fileSystemVMData = {path:e.detail.path} 110 let pane = this.getPaneByID("box-vm-events"); 111 this.litTabs?.activeByKey(pane.key); 112 if (e.detail.path) { 113 (pane.children.item(0) as any)!.fromStastics(this.selection) 114 } 115 }); 116 } 117 118 connectedCallback() { 119 this.nav = this.shadowRoot?.querySelector("#tabs")?.shadowRoot?.querySelector('.tab-nav-container') 120 let tabs: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#tabs') 121 let navRoot: HTMLDivElement | null | undefined = this.shadowRoot?.querySelector("#tabs")?.shadowRoot?.querySelector('.nav-root') 122 let search: HTMLDivElement | undefined | null = document.querySelector("body > sp-application")?.shadowRoot?.querySelector("div > div.search-container") 123 let timerShaft: HTMLDivElement | undefined | null = this.parentElement?.querySelector(".timer-shaft") 124 let spacer: HTMLDivElement | undefined | null = this.parentElement?.querySelector(".spacer") 125 let borderTop: number = 1; 126 let initialHeight = {tabs: `calc(30vh + 39px)`, node: "30vh"}; 127 this.nav!.onmousedown = (event) => { 128 (window as any).isSheetMove = true; 129 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = this.shadowRoot?.querySelectorAll("#tabs > lit-tabpane") 130 let preY = event.pageY; 131 let preHeight = tabs!.offsetHeight; 132 document.onmousemove = function (event) { 133 let moveY: number = preHeight - (event.pageY - preY) 134 litTabpane!.forEach((node: HTMLDivElement) => { 135 if (navRoot!.offsetHeight <= moveY && (search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight) <= (window.innerHeight - moveY)) { 136 tabs!.style.height = moveY + "px" 137 node!.style.height = (moveY - navRoot!.offsetHeight) + "px" 138 tabsPackUp!.name = "down" 139 } else if (navRoot!.offsetHeight >= moveY) { 140 tabs!.style.height = navRoot!.offsetHeight + "px" 141 node!.style.height = "0px" 142 tabsPackUp!.name = "up" 143 } else if ((search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight) >= (window.innerHeight - moveY)) { 144 tabs!.style.height = (window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - borderTop - spacer!.offsetHeight) + "px" 145 node!.style.height = (window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - navRoot!.offsetHeight - borderTop - spacer!.offsetHeight) + "px" 146 tabsPackUp!.name = "down" 147 } 148 }) 149 } 150 document.onmouseup = function () { 151 (window as any).isSheetMove = false; 152 litTabpane!.forEach((node: HTMLDivElement) => { 153 if (node!.style.height !== "0px" && tabs!.style.height != "") { 154 initialHeight.node = node!.style.height; 155 initialHeight.tabs = tabs!.style.height; 156 } 157 }) 158 this.onmousemove = null; 159 this.onmouseup = null; 160 } 161 } 162 let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>("#tabs > div > lit-icon:nth-child(1)") 163 let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector<LitIcon>("#tabs > div > lit-icon:nth-child(2)") 164 tabsOpenUp!.onclick = () => { 165 tabs!.style.height = (window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - borderTop) + "px" 166 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = this.shadowRoot?.querySelectorAll("#tabs > lit-tabpane") 167 litTabpane!.forEach((node: HTMLDivElement) => { 168 node!.style.height = (window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - navRoot!.offsetHeight - borderTop) + "px" 169 initialHeight.node = node!.style.height; 170 }) 171 initialHeight.tabs = tabs!.style.height; 172 tabsPackUp!.name = "down" 173 } 174 tabsPackUp!.onclick = () => { 175 let litTabpane: NodeListOf<HTMLDivElement> | undefined | null = this.shadowRoot?.querySelectorAll("#tabs > lit-tabpane") 176 if (tabsPackUp!.name == "down") { 177 tabs!.style.height = navRoot!.offsetHeight + "px" 178 litTabpane!.forEach((node: HTMLDivElement) => node!.style.height = "0px") 179 tabsPackUp!.name = "up"; 180 (window as any).isPackUpTable = true; 181 } else { 182 tabsPackUp!.name = "down" 183 tabs!.style.height = initialHeight.tabs; 184 litTabpane!.forEach((node: HTMLDivElement) => node!.style.height = initialHeight.node) 185 } 186 } 187 } 188 189 initHtml(): string { 190 return ` 191 <style> 192 :host([mode='hidden']){ 193 display: none; 194 } 195 :host{ 196 display: block; 197 background-color: rebeccapurple; 198 } 199 .tabHeight{ 200 height: 30vh; 201 background-color: var(--dark-background,#FFFFFF); 202 } 203 </style> 204 <div style="border-top: 1px solid var(--dark-border1,#D5D5D5);"> 205 <lit-tabs id="tabs" position="top-left" activekey="1" mode="card" > 206 <div slot="right" style="margin: 0 10px; color: var(--dark-icon,#606060);display: flex;align-items: center;"> 207 <lit-icon id="max-btn" name="vertical-align-top" style="font-weight: bold;cursor: pointer;margin-right: 5px" size="20"> 208 </lit-icon> 209 <lit-icon id="min-btn" name="down" style="font-weight: bold;cursor: pointer;" size="20"> 210 </lit-icon> 211 </div> 212 </lit-tabs> 213 </div>`; 214 } 215 216 displayThreadData = (data: ThreadStruct, scrollCallback: ((e: ThreadStruct) => void) | undefined, scrollWakeUp: (d: any) => void | undefined) => 217 this.displayTab<TabPaneCurrentSelection>("current-selection").setThreadData(data, scrollCallback, scrollWakeUp) 218 displayMemData = (data: ProcessMemStruct) => 219 this.displayTab<TabPaneCurrentSelection>("current-selection").setMemData(data); 220 displayFuncData = (data: FuncStruct, scrollCallback: Function) => 221 this.displayTab<TabPaneCurrentSelection>("current-selection").setFunctionData(data, scrollCallback); 222 displayCpuData = (data: CpuStruct, callback: ((data: WakeupBean | null) => void) | undefined = undefined, scrollCallback?: (data: CpuStruct) => void) => 223 this.displayTab<TabPaneCurrentSelection>("current-selection").setCpuData(data, callback, scrollCallback); 224 displayFlagData = (flagObj: Flag) => this.displayTab<TabPaneFlag>("box-flag").setFlagObj(flagObj); 225 displayFreqData = () => this.displayTab<TabPaneCurrentSelection>("box-freq").data = CpuFreqStruct.selectCpuFreqStruct; 226 displayCpuStateData = () => this.displayTab<TabPaneCurrentSelection>("cpu-state-click").data = SpFreqChart.selectStateStruct; 227 displayFreqLimitData = () => this.displayTab<TabPaneCurrentSelection>("box-freq-limit").data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct; 228 229 rangeSelect(selection: SelectionParam): boolean { 230 this.selection = selection; 231 Reflect.ownKeys(tabConfig).reverse().forEach(id => { 232 let element = tabConfig[id]; 233 if (element.require) { 234 if (element.require(selection)) { 235 let pane = this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`); 236 pane!.hidden = false; 237 } else { 238 this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`)!.hidden = true; 239 } 240 } else { 241 this.shadowRoot!.querySelector<LitTabpane>(`#${id as string}`)!.hidden = true; 242 } 243 }) 244 let firstPane = this.shadowRoot!.querySelector<LitTabpane>(`lit-tabpane[hidden='false']`); 245 if (firstPane) { 246 this.litTabs?.activeByKey(firstPane.key) 247 this.loadTabPaneData(firstPane.key) 248 this.setAttribute("mode", "max") 249 return true; 250 } else { 251 this.setAttribute("mode", "hidden") 252 return false; 253 } 254 } 255 256 loadTabPaneData(key: string) { 257 let component: any = this.shadowRoot?.querySelector<LitTabpane>(`#tabs lit-tabpane[key='${key}']`)?.children.item(0); 258 if (component) { 259 component.data = this.selection; 260 } 261 } 262 263 rowClickHandler(e: any) { 264 this.currentPaneID = e.target.parentElement.id 265 this.shadowRoot!.querySelectorAll<LitTabpane>(`lit-tabpane`) 266 .forEach(it => it.id != this.currentPaneID ? (it.hidden = true) : (it.hidden = false)); 267 let pane = this.getPaneByID("box-cpu-child"); 268 pane.closeable = true; 269 pane.hidden = false; 270 this.litTabs!.activeByKey(pane.key) 271 pane.tab = e.detail.title 272 let param = new BoxJumpParam(); 273 param.leftNs = this.selection!.leftNs; 274 param.rightNs = this.selection!.rightNs; 275 param.state = e.detail.state; 276 param.threadId = e.detail.threadId; 277 param.processId = e.detail.processId; 278 (pane.children.item(0) as TabPaneBoxChild).data = param; 279 } 280} 281