• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}