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 "../base-ui/menu/LitMainMenu.js"; 18import "../base-ui/icon/LitIcon.js"; 19import {SpMetrics} from "./component/SpMetrics.js"; 20import {SpHelp} from "./component/SpHelp.js"; 21import "./component/SpHelp.js"; 22import {SpQuerySQL} from "./component/SpQuerySQL.js"; 23import "./component/SpQuerySQL.js"; 24import {SpSystemTrace} from "./component/SpSystemTrace.js"; 25import {LitMainMenu, MenuItem} from "../base-ui/menu/LitMainMenu.js"; 26import {SpInfoAndStats} from "./component/SpInfoAndStas.js"; 27import "../base-ui/progress-bar/LitProgressBar.js"; 28import {LitProgressBar} from "../base-ui/progress-bar/LitProgressBar.js"; 29import {SpRecordTrace} from "./component/SpRecordTrace.js"; 30import {SpWelcomePage} from "./component/SpWelcomePage.js"; 31import {LitSearch} from "./component/trace/search/Search.js"; 32import {DbPool, threadPool} from "./database/SqlLite.js"; 33import "./component/trace/search/Search.js"; 34import "./component/SpWelcomePage.js"; 35import "./component/SpSystemTrace.js"; 36import "./component/SpRecordTrace.js"; 37import "./component/SpMetrics.js"; 38import "./component/SpInfoAndStas.js"; 39import "./component/trace/base/TraceRow.js"; 40import {info, log} from "../log/Log.js"; 41import {LitMainMenuGroup} from "../base-ui/menu/LitMainMenuGroup.js"; 42import {LitMainMenuItem} from "../base-ui/menu/LitMainMenuItem.js"; 43import {LitIcon} from "../base-ui/icon/LitIcon.js"; 44import {Cmd} from "../command/Cmd.js"; 45import {TraceRow} from "./component/trace/base/TraceRow.js"; 46 47@element('sp-application') 48export class SpApplication extends BaseElement { 49 static skinChange: Function | null | undefined = null; 50 static skinChange2: Function | null | undefined = null; 51 skinChangeArray: Array<Function> = []; 52 private icon: HTMLDivElement | undefined | null 53 private rootEL: HTMLDivElement | undefined | null 54 private spHelp: SpHelp | undefined | null 55 private keyCodeMap = { 56 61: true, 57 107: true, 58 109: true, 59 173: true, 60 187: true, 61 189: true, 62 }; 63 64 static get observedAttributes() { 65 return ["server", "sqlite", "wasm", "dark", "vs", "query-sql","subsection"] 66 } 67 68 get dark() { 69 return this.hasAttribute('dark'); 70 } 71 72 set dark(value) { 73 if (value) { 74 this.rootEL!.classList.add('dark'); 75 this.setAttribute('dark', ''); 76 } else { 77 this.rootEL!.classList.remove('dark'); 78 this.removeAttribute('dark'); 79 } 80 if (this.skinChangeArray.length > 0) { 81 this.skinChangeArray.forEach((item) => item(value)); 82 } 83 if (SpApplication.skinChange) { 84 SpApplication.skinChange(value); 85 } 86 if (SpApplication.skinChange2) { 87 SpApplication.skinChange2(value); 88 } 89 90 if (this.spHelp) { 91 this.spHelp.dark = value 92 } 93 } 94 95 get vs(): boolean { 96 return this.hasAttribute("vs") 97 } 98 99 set vs(isVs: boolean) { 100 if (isVs) { 101 this.setAttribute("vs", "") 102 } 103 } 104 105 get sqlite(): boolean { 106 return this.hasAttribute("sqlite") 107 } 108 109 get wasm(): boolean { 110 return this.hasAttribute("wasm") 111 } 112 113 get server(): boolean { 114 return this.hasAttribute("server") 115 } 116 117 set server(s: boolean) { 118 if (s) { 119 this.setAttribute('server', '') 120 } else { 121 this.removeAttribute('server') 122 } 123 } 124 125 get querySql(): boolean { 126 return this.hasAttribute("query-sql") 127 } 128 129 set querySql(isShowMetric) { 130 if (isShowMetric) { 131 this.setAttribute('query-sql','') 132 } else { 133 this.removeAttribute('query-sql') 134 } 135 } 136 137 set search(search: boolean) { 138 if (search) { 139 this.setAttribute('search', '') 140 } else { 141 this.removeAttribute('search') 142 } 143 } 144 145 get search(): boolean { 146 return this.hasAttribute("search") 147 } 148 149 addSkinListener(handler: Function) { 150 this.skinChangeArray.push(handler) 151 }; 152 153 removeSkinListener(handler: Function) { 154 this.skinChangeArray.splice(this.skinChangeArray.indexOf(handler), 1); 155 }; 156 157 initHtml(): string { 158 return ` 159 <style> 160 :host{ 161 162 } 163 .dark{ 164 --dark-background: #272C34; 165 --dark-background1: #424851; 166 --dark-background2: #262f3c; 167 --dark-background3: #292D33; 168 --dark-background4: #323841; 169 --dark-background5: #333840; 170 --dark-background6: rgba(82,145,255,0.2); 171 --dark-background7: #494d52; 172 --dark-background8: #5291FF; 173 --dark-color: rgba(255,255,255,0.6); 174 --dark-color1: rgba(255,255,255,0.86); 175 --dark-color2: rgba(255,255,255,0.9); 176 --dark-border: #474F59; 177 --dark-color3:#4694C2; 178 --dark-color4:#5AADA0; 179 --dark-border1: #454E5A; 180 --bark-expansion:#0076FF; 181 --bark-prompt:#9e9e9e; 182 --dark-icon:#adafb3; 183 --dark-img: url('img/dark_pic.png'); 184 background: #272C34; 185 color: #FFFFFF; 186 } 187 .root{ 188 display: grid; 189 grid-template-rows: min-content 1fr; 190 grid-template-columns: min-content 1fr; 191 grid-template-areas: 'm s' 192 'm b'; 193 height: 100vh; 194 width: 100vw; 195 } 196 .filedrag::after { 197 content: 'Drop the trace file to open it'; 198 position: fixed; 199 z-index: 2001; 200 top: 0; 201 left: 0; 202 right: 0; 203 bottom: 0; 204 border: 5px dashed var(--dark-color1,#404854); 205 text-align: center; 206 font-size: 3rem; 207 line-height: 100vh; 208 background: rgba(255, 255, 255, 0.5); 209 } 210 .menu{ 211 grid-area: m; 212 /*transition: all 0.2s;*/ 213 box-shadow: 4px 0px 20px rgba(0,0,0,0.05); 214 z-index: 2000; 215 } 216 .search-container{ 217 z-index: 10; 218 position: relative; 219 } 220 .progress{ 221 bottom: 0; 222 position: absolute; 223 height: 1px; 224 left: 0; 225 right: 0; 226 } 227 :host(:not([search])) .search-container { 228 display: none; 229 } 230 231 :host(:not([search])) .search-container .search { 232 background-color: var(--dark-background5,#F6F6F6); 233 } 234 .search{ 235 grid-area: s; 236 background-color: var(--dark-background,#FFFFFF); 237 height: 48px; 238 display: flex; 239 justify-content: center; 240 align-items: center; 241 242 } 243 .search .search-bg{ 244 background-color: var(--dark-background5,#fff); 245 border-radius: 40px; 246 padding: 3px 20px; 247 display: flex; 248 justify-content: center; 249 align-items: center; 250 border: 1px solid var(--dark-border,#c5c5c5); 251 } 252 .search input{ 253 outline: none; 254 border: 0px; 255 background-color: transparent; 256 font-size: inherit; 257 color: var(--dark-color,#666666); 258 width: 30vw; 259 height: auto; 260 vertical-align:middle; 261 line-height:inherit; 262 height:inherit; 263 padding: 6px 6px 6px 6px}; 264 max-height: inherit; 265 box-sizing: border-box; 266 267 } 268 ::placeholder { /* CSS 3 標準 */ 269 color: #b5b7ba; 270 font-size: 1em; 271 } 272 .search input::placeholder { 273 color: #b5b7ba; 274 font-size: 1em; 275 } 276 .content{ 277 grid-area: b; 278 background-color: #ffffff; 279 height: 100%; 280 overflow: auto; 281 position:relative; 282 } 283 .sheet{ 284 285 } 286 .sidebar-button{ 287 position: absolute; 288 top: 0; 289 left: 0; 290 background-color: var(--dark-background1,#FFFFFF); 291 height: 100%; 292 border-radius: 0 5px 5px 0; 293 width: 48px; 294 display: flex; 295 align-content: center; 296 justify-content: center; 297 cursor: pointer; 298 } 299 :host{ 300 font-size: inherit; 301 display: inline-block; 302 transition: .3s; 303 } 304 :host([spin]){ 305 animation: rotate 1.75s linear infinite; 306 } 307 @keyframes rotate { 308 to{ 309 transform: rotate(360deg); 310 } 311 } 312 .icon{ 313 display: block; 314 width: 1em; 315 height: 1em; 316 margin: auto; 317 fill: currentColor; 318 overflow: hidden; 319 font-size: 20px; 320 color: var(--dark-color1,#4D4D4D); 321 } 322 </style> 323 <div class="root"> 324 <lit-main-menu id="main-menu" class="menu" data=''></lit-main-menu> 325 <div class="search-container"> 326 <div class="search" style="position: relative;"> 327 <div class="sidebar-button" style="width: 0"> 328 <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 1024 1024"> 329 <use id="use" xlink:href="./base-ui/icon.svg#icon-menu"></use> 330 </svg> 331 </div> 332 <lit-search id="lit-search"></lit-search> 333 </div> 334 <lit-progress-bar class="progress"></lit-progress-bar> 335 </div> 336 <div id="app-content" class="content"> 337 <sp-welcome style="visibility:visible;top:0px;left:0px;position:absolute;z-index: 100" id="sp-welcome"> 338 </sp-welcome> 339 <sp-system-trace style="visibility:visible;" id="sp-system-trace"> 340 </sp-system-trace> 341 <sp-record-trace style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 102" id="sp-record-trace"> 342 </sp-record-trace> 343 <sp-metrics style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 97" id="sp-metrics"> 344 </sp-metrics> 345 <sp-query-sql style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 98" id="sp-query-sql"> 346 </sp-query-sql> 347 <sp-info-and-stats style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0;left:0;right:0;bottom:0;position:absolute;z-index: 99" id="sp-info-and-stats"> 348 </sp-info-and-stats> 349 <sp-help style="width:100%;height:100%;overflow:auto;visibility:hidden;top:0px;left:0px;right:0;bottom:0px;position:absolute;z-index: 103" id="sp-help"> 350 </sp-help> 351 </div> 352 </div> 353 `; 354 } 355 356 initElements() { 357 let that = this; 358 this.querySql = true 359 this.rootEL = this.shadowRoot!.querySelector<HTMLDivElement>(".root") 360 let spWelcomePage = this.shadowRoot!.querySelector("#sp-welcome") as SpWelcomePage 361 let spMetrics = this.shadowRoot!.querySelector<SpMetrics>("#sp-metrics") as SpMetrics // new SpMetrics(); 362 let spQuerySQL = this.shadowRoot!.querySelector<SpQuerySQL>("#sp-query-sql") as SpQuerySQL // new SpQuerySQL(); 363 let spInfoAndStats = this.shadowRoot!.querySelector<SpInfoAndStats>("#sp-info-and-stats") as SpInfoAndStats // new SpInfoAndStats(); 364 365 let spSystemTrace = this.shadowRoot!.querySelector<SpSystemTrace>("#sp-system-trace") 366 this.spHelp = this.shadowRoot!.querySelector<SpHelp>("#sp-help") 367 let spRecordTrace = this.shadowRoot!.querySelector<SpRecordTrace>("#sp-record-trace") 368 let appContent = this.shadowRoot?.querySelector('#app-content') as HTMLDivElement; 369 let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu 370 let menu = mainMenu.shadowRoot?.querySelector('.menu-button') as HTMLDivElement 371 let progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar 372 let litSearch = this.shadowRoot?.querySelector('#lit-search') as LitSearch 373 let search = this.shadowRoot?.querySelector('.search-container') as HTMLElement 374 let sidebarButton: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button') 375 let childNodes = [spSystemTrace, spRecordTrace, spWelcomePage, spMetrics, spQuerySQL, spInfoAndStats, this.spHelp] 376 litSearch.addEventListener("focus", () => { 377 spSystemTrace!.keyboardEnable = false 378 }) 379 litSearch.addEventListener('blur', () => { 380 spSystemTrace!.keyboardEnable = true 381 }) 382 litSearch.addEventListener("previous-data", (ev: any) => { 383 litSearch.index = spSystemTrace!.showStruct(true, litSearch.index, litSearch.list); 384 litSearch.blur(); 385 }) 386 litSearch.addEventListener("next-data", (ev: any) => { 387 litSearch.index = spSystemTrace!.showStruct(false, litSearch.index, litSearch.list); 388 litSearch.blur(); 389 }) 390 litSearch.valueChangeHandler = (value: string) => { 391 if (value.length > 0) { 392 let list = spSystemTrace!.searchCPU(value); 393 spSystemTrace!.searchFunction(list, value).then((mixedResults) => { 394 if(litSearch.searchValue != ""){ 395 litSearch.list = mixedResults 396 } 397 }) 398 } else { 399 litSearch.list = []; 400 spSystemTrace?.visibleRows.forEach(it => { 401 it.highlight = false; 402 it.draw(); 403 }); 404 spSystemTrace?.timerShaftEL?.removeTriangle("inverted"); 405 } 406 } 407 spSystemTrace?.addEventListener("previous-data", (ev: any) => { 408 litSearch.index = spSystemTrace!.showStruct(true, litSearch.index, litSearch.list); 409 }) 410 spSystemTrace?.addEventListener("next-data", (ev: any) => { 411 litSearch.index = spSystemTrace!.showStruct(false, litSearch.index, litSearch.list); 412 }) 413 //打开侧边栏 414 sidebarButton!.onclick = (e) => { 415 let menu: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#main-menu') 416 let menuButton: HTMLElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button') 417 if (menu) { 418 menu.style.width = `248px` 419 // @ts-ignore 420 menu.style.zIndex = 2000; 421 menu.style.display = `flex` 422 } 423 if (menuButton) { 424 menuButton.style.width = `0px` 425 } 426 } 427 let icon: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector("#main-menu")?.shadowRoot?.querySelector("div.header > div") 428 icon!.style.pointerEvents = 'none' 429 icon!.onclick = (e) => { 430 let menu: HTMLElement | undefined | null = this.shadowRoot?.querySelector("#main-menu") 431 let menuButton: HTMLElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button') 432 if (menu) { 433 menu.style.width = `0px` 434 menu.style.display = `flex` 435 // @ts-ignore 436 menu.style.zIndex = 0 437 } 438 if (menuButton) { 439 menuButton.style.width = `48px` 440 } 441 } 442 443 function showContent(showNode: HTMLElement) { 444 if (showNode === spSystemTrace) { 445 menu!.style.pointerEvents = 'auto' 446 sidebarButton!.style.pointerEvents = 'auto' 447 that.search = true 448 } else { 449 menu!.style.pointerEvents = 'none' 450 sidebarButton!.style.pointerEvents = 'none' 451 that.search = litSearch.isLoading 452 } 453 log("show pages" + showNode.id) 454 childNodes.forEach((node) => { 455 if (node === showNode) { 456 showNode.style.visibility = 'visible' 457 } else { 458 node!.style.visibility = 'hidden' 459 } 460 }) 461 } 462 463 function postLog(filename: string, fileSize: string) { 464 log("postLog filename is: " + filename + " fileSize: " + fileSize) 465 fetch(`https://${window.location.host.split(':')[0]}:9000/logger`, { 466 method: 'POST', 467 headers: { 468 'Content-Type': 'application/json', 469 }, 470 body: JSON.stringify({ 471 fileName: filename, 472 fileSize: fileSize 473 }), 474 }).then(response => response.json()).then(data => { 475 }).catch((error) => { 476 }); 477 } 478 479 function handleServerMode(ev: any, showFileName: string, fileSize: string, fileName: string, isClickHandle?: boolean) { 480 threadPool.init("server").then(() => { 481 info("init server ok"); 482 litSearch.setPercent("parse trace", 1); 483 // Load the trace file and send it to the background parse to return the db file path 484 const fd = new FormData() 485 that.freshMenuDisable(true) 486 if (that.vs && isClickHandle) { 487 fd.append("convertType", "vsUpload"); 488 fd.append('filePath', ev as any) 489 } else { 490 fd.append('file', ev as any) 491 } 492 let uploadPath = `https://${window.location.host.split(':')[0]}:9000/upload` 493 if (that.vs) { 494 uploadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}/upload` 495 } 496 info("upload trace") 497 let dbName = ""; 498 fetch(uploadPath, { 499 method: 'POST', 500 body: fd, 501 }).then(res => { 502 litSearch.setPercent("load database", 5); 503 if (res.ok) { 504 info(" server Parse trace file success"); 505 let menus = [ 506 { 507 title: `${showFileName} (${fileSize}M)`, 508 icon: "file-fill", 509 clickHandler: function () { 510 that.search = true 511 showContent(spSystemTrace!) 512 } 513 }, 514 { 515 title: "DownLoad", 516 icon: "download", 517 clickHandler: function () { 518 if (that.vs) { 519 that.vsDownload(mainMenu, fileName, true, dbName); 520 } else { 521 that.download(mainMenu, fileName, true, dbName); 522 } 523 } 524 } 525 ]; 526 527 if (that.querySql) { 528 if (spQuerySQL) { 529 spQuerySQL.reset() 530 menus.push({ 531 title: "Query (SQL)", icon: "filesearch", clickHandler: () => { 532 showContent(spQuerySQL) 533 } 534 }); 535 } 536 537 if (spMetrics) { 538 spMetrics.reset() 539 menus.push({ 540 title: "Metrics", icon: "metric", clickHandler: () => { 541 showContent(spMetrics) 542 } 543 }); 544 } 545 546 if (spInfoAndStats) { 547 menus.push({ 548 title: "Info and stats", icon: "info", clickHandler: () => { 549 showContent(spInfoAndStats) 550 } 551 }); 552 } 553 } 554 555 mainMenu.menus!.splice(1, 1, { 556 collapsed: false, 557 title: "Current Trace", 558 describe: "Actions on the current trace", 559 children: menus 560 }) 561 562 that.freshMenuDisable(true) 563 return res.text(); 564 } else { 565 if (res.status == 404) { 566 info(" server Parse trace file failed"); 567 litSearch.setPercent("This File is not supported!", -1) 568 progressEL.loading = false; 569 that.freshMenuDisable(false) 570 return Promise.reject(); 571 } 572 } 573 }).then(res => { 574 if (res != undefined) { 575 dbName = res; 576 info("get trace db"); 577 let loadPath = `https://${window.location.host.split(':')[0]}:9000` 578 if (that.vs) { 579 loadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}` 580 } 581 spSystemTrace!.loadDatabaseUrl(loadPath + res, (command: string, percent: number) => { 582 info("setPercent :" + command + "percent :" + percent); 583 litSearch.setPercent(command + ' ', percent); 584 }, (res) => { 585 info("loadDatabaseUrl success"); 586 litSearch.setPercent("", 101); 587 progressEL.loading = false; 588 that.freshMenuDisable(false) 589 }) 590 } else { 591 litSearch.setPercent("", 101) 592 progressEL.loading = false; 593 that.freshMenuDisable(false) 594 } 595 spInfoAndStats.initInfoAndStatsData(); 596 }) 597 }) 598 } 599 600 function handleWasmMode(ev: any, showFileName: string, fileSize: string, fileName: string) { 601 litSearch.setPercent("", 1); 602 threadPool.init("wasm").then(res => { 603 let reader = new FileReader(); 604 reader.readAsArrayBuffer(ev as any) 605 reader.onloadend = function (ev) { 606 info("read file onloadend"); 607 litSearch.setPercent("ArrayBuffer loaded ", 2); 608 that.freshMenuDisable(true) 609 let menus = [ 610 { 611 title: `${showFileName} (${fileSize}M)`, 612 icon: "file-fill", 613 clickHandler: function () { 614 that.search = true 615 showContent(spSystemTrace!) 616 } 617 }, 618 { 619 title: "DownLoad", 620 icon: "download", 621 clickHandler: function () { 622 if (that.vs) { 623 that.vsDownload(mainMenu, fileName, false); 624 } else { 625 that.download(mainMenu, fileName, false); 626 } 627 } 628 } 629 ]; 630 if (that.querySql) { 631 if (spQuerySQL) { 632 spQuerySQL.reset() 633 menus.push({ 634 title: "Query (SQL)", icon: "filesearch", clickHandler: () => { 635 showContent(spQuerySQL) 636 } 637 }); 638 } 639 640 if (spMetrics) { 641 spMetrics.reset() 642 menus.push({ 643 title: "Metrics", icon: "metric", clickHandler: () => { 644 showContent(spMetrics) 645 } 646 }); 647 } 648 649 if (spInfoAndStats) { 650 menus.push({ 651 title: "Info and stats", icon: "info", clickHandler: () => { 652 showContent(spInfoAndStats) 653 } 654 }); 655 } 656 } 657 mainMenu.menus!.splice(1, 1, { 658 collapsed: false, 659 title: "Current Trace", 660 describe: "Actions on the current trace", 661 children: menus 662 }) 663 mainMenu.menus!.splice(2, 1, { 664 collapsed: false, 665 title: 'Support', 666 describe: 'Support', 667 children: [ 668 { 669 title: "Help Documents", 670 icon: "smart-help", 671 clickHandler: function (item: MenuItem) { 672 that.search = false 673 that.spHelp!.dark = that.dark 674 showContent(that.spHelp!) 675 } 676 }, 677 ] 678 }) 679 let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json` 680 if (that.vs) { 681 wasmUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}/wasm.json` 682 } 683 spSystemTrace!.loadDatabaseArrayBuffer(this.result as ArrayBuffer, wasmUrl,(command: string, percent: number) => { 684 info("setPercent :" + command + "percent :" + percent); 685 litSearch.setPercent(command + ' ', percent); 686 }, (res) => { 687 if (res.status) { 688 info("loadDatabaseArrayBuffer success"); 689 showContent(spSystemTrace!) 690 litSearch.setPercent("", 101); 691 progressEL.loading = false; 692 that.freshMenuDisable(false) 693 } else { 694 info("loadDatabaseArrayBuffer failed"); 695 litSearch.setPercent("This File is not supported!", -1) 696 progressEL.loading = false; 697 that.freshMenuDisable(false) 698 mainMenu.menus!.splice(1, 1); 699 mainMenu.menus = mainMenu.menus!; 700 } 701 spInfoAndStats.initInfoAndStatsData(); 702 }) 703 } 704 }) 705 } 706 707 function openTraceFile(ev: any, isClickHandle?: boolean) { 708 info("openTraceFile") 709 if (that.vs && isClickHandle) { 710 Cmd.openFileDialog().then((res: string) => { 711 if (res != "") { 712 litSearch.clear(); 713 showContent(spSystemTrace!) 714 that.search = true 715 progressEL.loading = true 716 let openResult = JSON.parse(res) 717 let fileName = openResult.fileName 718 let fileSize = (openResult.fileSize / 1048576).toFixed(1) 719 let showFileName = fileName.lastIndexOf('.') == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.')) 720 document.title = `${showFileName} (${fileSize}M)` 721 TraceRow.rangeSelectObject = undefined; 722 if (that.server) { 723 info("Parse trace using server mode ") 724 handleServerMode(openResult.filePath, showFileName, fileSize, fileName, isClickHandle); 725 return; 726 } 727 if (that.wasm) { 728 info("Parse trace using wasm mode ") 729 const vsUpload = new FormData(); 730 vsUpload.append("convertType", "vsUpload"); 731 vsUpload.append("isTransform", ""); 732 vsUpload.append('filePath', openResult.filePath) 733 info("openResult.filePath ", openResult.filePath) 734 litSearch.setPercent("upload file ", 1); 735 Cmd.uploadFile(vsUpload, (response:Response) => { 736 if (response.ok) { 737 response.text().then(traceFile => { 738 let traceFilePath = `http://${window.location.host.split(':')[0]}:${window.location.port}` + traceFile 739 fetch(traceFilePath).then(res => { 740 res.arrayBuffer().then(arrayBuf => { 741 handleWasmMode( new File([arrayBuf],fileName), showFileName, fileSize, fileName); 742 }) 743 }) 744 }); 745 } 746 }) 747 return; 748 } 749 } else { 750 return; 751 } 752 }) 753 } else { 754 litSearch.clear(); 755 showContent(spSystemTrace!) 756 that.search = true 757 progressEL.loading = true 758 let fileName = (ev as any).name 759 let fileSize = ((ev as any).size / 1048576).toFixed(1) 760 postLog(fileName, fileSize) 761 let showFileName = fileName.lastIndexOf('.') == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.')) 762 document.title = `${showFileName} (${fileSize}M)` 763 TraceRow.rangeSelectObject = undefined; 764 if (that.server) { 765 info("Parse trace using server mode ") 766 handleServerMode(ev, showFileName, fileSize, fileName); 767 return; 768 } 769 if (that.sqlite) { 770 info("Parse trace using sql mode") 771 litSearch.setPercent("", 0); 772 threadPool.init("sqlite").then(res => { 773 let reader = new FileReader(); 774 reader.readAsArrayBuffer(ev as any) 775 reader.onloadend = function (ev) { 776 spSystemTrace!.loadDatabaseArrayBuffer(this.result as ArrayBuffer, "",(command: string, percent: number) => { 777 info("setPercent :" + command + "percent :" + percent); 778 litSearch.setPercent(command + ' ', percent); 779 }, () => { 780 litSearch.setPercent("", 101); 781 progressEL.loading = false; 782 that.freshMenuDisable(false) 783 }) 784 } 785 }) 786 return; 787 } 788 if (that.wasm) { 789 info("Parse trace using wasm mode ") 790 handleWasmMode(ev, showFileName, fileSize, fileName); 791 return; 792 } 793 } 794 } 795 796 mainMenu.menus = [ 797 { 798 collapsed: false, 799 title: 'Navigation', 800 describe: 'Open or record a new trace', 801 children: [ 802 { 803 title: "Open trace file", 804 icon: "folder", 805 fileChoose: !that.vs, 806 fileHandler: function (ev: InputEvent) { 807 openTraceFile(ev.detail as any); 808 }, 809 clickHandler: function (hand: any) { 810 openTraceFile(hand, true); 811 } 812 }, 813 { 814 title: "Record new trace", icon: "copyhovered", clickHandler: function (item: MenuItem) { 815 if (that.vs) { 816 spRecordTrace!.vs = true; 817 spRecordTrace!.startRefreshDeviceList() 818 } 819 showContent(spRecordTrace!) 820 } 821 } 822 ] 823 }, 824 { 825 collapsed: false, 826 title: 'Support', 827 describe: 'Support', 828 children: [ 829 { 830 title: "Help Documents", 831 icon: "smart-help", 832 clickHandler: function (item: MenuItem) { 833 that.search = false 834 that.spHelp!.dark = that.dark 835 showContent(that.spHelp!) 836 } 837 }, 838 ] 839 } 840 ] 841 842 let body = document.querySelector("body"); 843 body!.addEventListener('dragover', (e: any) => { 844 e.preventDefault(); 845 e.stopPropagation(); 846 if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind === "file") { 847 e.dataTransfer.dropEffect = 'copy'; 848 if (!this.rootEL!.classList.contains('filedrag')) { 849 this.rootEL!.classList.add("filedrag") 850 } 851 } 852 }, false); 853 body!.addEventListener("dragleave", (e) => { 854 e.stopPropagation(); 855 e.preventDefault(); 856 if (this.rootEL!.classList.contains('filedrag')) { 857 this.rootEL!.classList.remove("filedrag") 858 } 859 }, false); 860 body!.addEventListener('drop', (e: any) => { 861 e.preventDefault(); 862 e.stopPropagation(); 863 if (this.rootEL!.classList.contains('filedrag')) { 864 this.rootEL!.classList.remove("filedrag") 865 } 866 if (e.dataTransfer.items !== undefined && e.dataTransfer.items.length > 0) { 867 let item = e.dataTransfer.items[0]; 868 if (item.webkitGetAsEntry()?.isFile) { 869 openTraceFile(item.getAsFile()); 870 } else if (item.webkitGetAsEntry()?.isDirectory) { 871 litSearch.setPercent("This File is not supported!", -1) 872 progressEL.loading = false; 873 that.freshMenuDisable(false) 874 mainMenu.menus!.splice(1, 1); 875 mainMenu.menus = mainMenu.menus!; 876 spSystemTrace!.reset(null); 877 } 878 } 879 }, false); 880 document.addEventListener("keydown", (event) => { 881 const e = event || window.event; 882 const ctrlKey = e.ctrlKey || e.metaKey; 883 if (ctrlKey && (this.keyCodeMap as any)[e.keyCode]) { 884 e.preventDefault(); 885 } else if (e.detail) { // Firefox 886 event.returnValue = false; 887 } 888 }) 889 document.body.addEventListener('wheel', (e) => { 890 if (e.ctrlKey) { 891 if (e.deltaY < 0) { 892 e.preventDefault(); 893 return false; 894 } 895 if (e.deltaY > 0) { 896 e.preventDefault(); 897 return false; 898 } 899 } 900 }, {passive: false}); 901 } 902 903 904 private download(mainMenu: LitMainMenu, fileName: string, isServer: boolean, dbName?: string) { 905 let a = document.createElement("a"); 906 if (isServer) { 907 if (dbName != "") { 908 let file = dbName?.substring(0, dbName?.lastIndexOf(".")) + fileName.substring(fileName.lastIndexOf(".")); 909 a.href = `https://${window.location.host.split(':')[0]}:9000` + file 910 } else { 911 return; 912 } 913 } else { 914 a.href = URL.createObjectURL(new Blob([DbPool.sharedBuffer!])); 915 } 916 a.download = fileName; 917 a.click() 918 let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll<LitMainMenuGroup>("lit-main-menu-group"); 919 querySelectorAll!.forEach((menuGroup) => { 920 let attribute = menuGroup.getAttribute("title"); 921 if (attribute === "Current Trace") { 922 let querySelectors = menuGroup.querySelectorAll<LitMainMenuItem>("lit-main-menu-item"); 923 querySelectors.forEach(item => { 924 if (item.getAttribute("title") == "DownLoad") { 925 item!.setAttribute("icon", "convert-loading"); 926 let querySelector1 = 927 item!.shadowRoot?.querySelector(".icon") as LitIcon; 928 querySelector1.setAttribute('spin', '') 929 } 930 }) 931 } 932 }) 933 window.URL.revokeObjectURL(a.href); 934 let timer = setInterval(function () { 935 let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll<LitMainMenuGroup>("lit-main-menu-group"); 936 querySelectorAll!.forEach((menuGroup) => { 937 let attribute = menuGroup.getAttribute("title"); 938 if (attribute === "Current Trace") { 939 let querySelectors = menuGroup.querySelectorAll<LitMainMenuItem>("lit-main-menu-item"); 940 querySelectors.forEach(item => { 941 if (item.getAttribute("title") == "DownLoad") { 942 item!.setAttribute("icon", "download"); 943 let querySelector1 = 944 item!.shadowRoot?.querySelector(".icon") as LitIcon; 945 querySelector1.removeAttribute("spin"); 946 } 947 }) 948 clearInterval(timer); 949 } 950 }) 951 }, 4000); 952 } 953 954 private vsDownload(mainMenu: LitMainMenu, fileName: string, isServer: boolean, dbName?: string) { 955 Cmd.showSaveFile((filePath: string) => { 956 if (filePath != "") { 957 let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll<LitMainMenuGroup>("lit-main-menu-group"); 958 querySelectorAll!.forEach((menuGroup) => { 959 let attribute = menuGroup.getAttribute("title"); 960 if (attribute === "Current Trace") { 961 let querySelectors = menuGroup.querySelectorAll<LitMainMenuItem>("lit-main-menu-item"); 962 querySelectors.forEach(item => { 963 if (item.getAttribute("title") == "DownLoad") { 964 item!.setAttribute("icon", "convert-loading"); 965 let querySelector1 = 966 item!.shadowRoot?.querySelector(".icon") as LitIcon; 967 querySelector1.setAttribute('spin', '') 968 } 969 }) 970 } 971 }) 972 if (isServer) { 973 if (dbName != "") { 974 let file = dbName?.substring(0, dbName?.lastIndexOf(".")) + fileName.substring(fileName.lastIndexOf(".")); 975 Cmd.copyFile(file, filePath, (res: Response) => { 976 this.stopDownLoading(mainMenu); 977 }) 978 } 979 } else { 980 const fd = new FormData() 981 fd.append("convertType", "download") 982 fd.append("filePath", filePath) 983 fd.append('file', new File([DbPool.sharedBuffer!], fileName)) 984 Cmd.uploadFile(fd, (res: Response) => { 985 if (res.ok) { 986 this.stopDownLoading(mainMenu); 987 } 988 }) 989 } 990 } 991 }) 992 } 993 994 private stopDownLoading(mainMenu: LitMainMenu) { 995 let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll<LitMainMenuGroup>("lit-main-menu-group"); 996 querySelectorAll!.forEach((menuGroup) => { 997 let attribute = menuGroup.getAttribute("title"); 998 if (attribute === "Current Trace") { 999 let querySelectors = menuGroup.querySelectorAll<LitMainMenuItem>("lit-main-menu-item"); 1000 querySelectors.forEach(item => { 1001 if (item.getAttribute("title") == "DownLoad") { 1002 item!.setAttribute("icon", "download"); 1003 let querySelector1 = 1004 item!.shadowRoot?.querySelector(".icon") as LitIcon; 1005 querySelector1.removeAttribute("spin"); 1006 } 1007 }) 1008 } 1009 }) 1010 } 1011 1012 freshMenuDisable(disable: boolean) { 1013 let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu 1014 // @ts-ignore 1015 mainMenu.menus[0].children[0].disabled = disable 1016 mainMenu.menus = mainMenu.menus; 1017 } 1018}