• 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/select/LitSelect.js";
18import "../../../../base-ui/select/LitSelectOption.js";
19import '../../../../base-ui/icon/LitIcon.js'
20import {LitIcon} from "../../../../base-ui/icon/LitIcon.js";
21import "../../../../base-ui/popover/LitPopoverV.js"
22import {LitCheckBox} from "../../../../base-ui/checkbox/LitCheckBox.js";
23
24export interface FilterData {
25    inputValue: string,
26    firstSelect: string | null | undefined,
27    secondSelect: string | null | undefined,
28    mark: boolean | null | undefined,
29    icon: string | null,
30    type: string,
31}
32
33export interface MiningData {
34    type: string,
35    item: any | null | undefined,
36    remove?: Array<any> | null | undefined,
37}
38
39@element('tab-pane-filter')
40export class TabPaneFilter extends BaseElement {
41    private filterInputEL: HTMLInputElement | null | undefined;
42    private firstSelectEL: HTMLSelectElement | null | undefined;
43    private secondSelectEL: HTMLSelectElement | null | undefined;
44    private markButtonEL: HTMLButtonElement | null | undefined;
45    private iconEL: LitIcon | null | undefined;
46    private statisticsName: HTMLDivElement | null | undefined;
47    private getFilter: ((e: FilterData) => void) | undefined;
48    private getMining: ((e: MiningData) => void) | undefined;
49    private getLibrary: ((e: MiningData) => void) | undefined;
50    private getCallTree: ((e: any) => void) | undefined;
51    private getCallTreeConstraints: ((e: any) => void) | undefined;
52    private getStatisticsType: ((e: any) => void) | undefined;
53
54    private cutList: Array<any> | undefined;
55    private libraryList: Array<any> | undefined;
56
57    filterData(type:string,data:object = {}){
58        return {
59            type: type,
60            inputValue: this.filterInputEL!.value,
61            firstSelect: this.firstSelectEL?.value,
62            secondSelect: this.secondSelectEL?.value,
63            mark: false,
64            icon: this.icon,
65            ...data
66        }
67    }
68
69    initElements(): void {
70        this.cutList = [];
71        this.libraryList = [];
72        this.filterInputEL = this.shadowRoot?.querySelector("#filter-input")
73        this.markButtonEL = this.shadowRoot?.querySelector("#mark")
74        this.iconEL = this.shadowRoot?.querySelector<LitIcon>("#icon")
75        this.statisticsName = this.shadowRoot?.querySelector<HTMLDivElement>(".statistics-name");
76        this.iconEL!.onclick = (e) => {
77            if (this.iconEL!.name == "statistics") {
78                this.iconEL!.name = "menu";
79                this.iconEL!.size = 18;
80                if (this.getFilter) {
81                    this.getFilter(this.filterData("icon"))
82                }
83            } else if (this.iconEL!.name == "menu") {
84                this.iconEL!.name = "statistics";
85                this.iconEL!.size = 16;
86                if (this.getFilter) {
87                    this.getFilter(this.filterData("icon"))
88                }
89            }
90        }
91
92        this.markButtonEL!.onclick = (e) => {
93            if (this.getFilter) {
94                this.getFilter(this.filterData("mark",{mark: true}))
95            }
96        }
97
98        this.filterInputEL?.addEventListener("keyup", (event: any) => {
99            if (event.keyCode == 13) {
100                if (this.getFilter) {
101                    this.getFilter(this.filterData("inputValue",{inputValue: event.target.value}))
102                }
103            }
104            event.stopPropagation();
105        });
106
107        this.filterInputEL?.addEventListener("keypress", (event: any) => {
108            event.stopPropagation();
109        });
110
111        this.setSelectList()
112
113        this.initializeCallTree()
114
115        this.initializeTreeConstraints()
116
117        this.initializeMining()
118
119        this.initializeLibrary()
120
121        this.shadowRoot!.querySelectorAll<HTMLDivElement>(".mining-button").forEach((e, idx) => {
122            e!.onclick = (ev) => {
123                if (idx == 0) {
124                    const restoreList = this.cutList!.filter(item => item.highlight === true)
125                    const list = this.cutList!.filter(item => item.highlight === false)
126                    this.cutList = list;
127                    if (this.getMining) {
128                        this.getMining({type: "button", item: "restore", remove: restoreList});
129                    }
130                    this.initializeMining();
131                }
132            }
133        })
134        this.shadowRoot!.querySelector<HTMLDivElement>(".library-button")!.onclick = (ev)=>{
135            const restoreList = this.libraryList!.filter(item => item.highlight === true)
136            const list = this.libraryList!.filter(item => item.highlight === false)
137            this.libraryList = list;
138            if (this.getLibrary) {
139                this.getLibrary({type: "button", item: "restore", remove: restoreList});
140            }
141            this.initializeLibrary();
142        }
143
144        this.shadowRoot!.querySelector<HTMLDivElement>("#data-mining")!.onclick = (e)=>{
145            if (this.getMining) {
146                this.getMining({type: "button", item: "symbol"});
147            }
148        }
149        this.shadowRoot!.querySelector<HTMLDivElement>("#data-library")!.onclick = (e)=>{
150            if (this.getLibrary) {
151                this.getLibrary({type: "button", item: "library"});
152            }
153        }
154        this.shadowRoot!.querySelector<HTMLDivElement>(".sort")!.onclick =(e)=>{
155            let statisticsType = this.statisticsName!.textContent == "Statistics by Operation"
156            this.statisticsName!.textContent = statisticsType?"Statistics by Thread":"Statistics by Operation";
157            if (this.getStatisticsType) {
158                this.getStatisticsType(statisticsType?"thread":"operation");
159            }
160        }
161    }
162
163    set firstSelect(value: string) {
164        this.firstSelectEL!.value = value;
165    }
166
167    get firstSelect() {
168        return this.firstSelectEL?.value || ""
169    }
170
171    set secondSelect(value: string) {
172        this.secondSelectEL!.value = value;
173    }
174
175    get secondSelect() {
176        return this.secondSelectEL?.value || ""
177    }
178
179    set filterValue(value: string) {
180        this.filterInputEL!.value = value;
181    }
182
183    get filterValue() {
184        return this.filterInputEL!.value
185    }
186
187    get inputPlaceholder() {
188        return this.getAttribute("inputPlaceholder") || "Detail Filter";
189    }
190
191    get icon() {
192        if (this.getAttribute("icon") != "false") {
193            if (this.iconEL!.name == "statistics") {
194                return "tree"
195            } else if (this.iconEL!.name == "menu") {
196                return "block"
197            } else {
198                return ""
199            }
200        } else {
201            return "";
202        }
203    }
204
205    set icon(value: string) {
206        if (value == "block") {
207            this.iconEL!.name = "menu";
208            this.iconEL!.size = 18;
209        } else if (value == "tree") {
210            this.iconEL!.name = "statistics";
211            this.iconEL!.size = 16;
212        }
213    }
214
215    get disabledMining(){
216        return this.hasAttribute("disabledMining")
217    }
218
219    set disabledMining(value:boolean){
220        if (value) {
221            this.setAttribute("disabledMining","")
222        }else {
223            this.removeAttribute("disabledMining")
224        }
225    }
226
227    getCallTreeData(getCallTree: (v: any) => void) {
228        this.getCallTree = getCallTree
229    }
230
231    getCallTreeConstraintsData(getCallTreeConstraints: (v: any) => void) {
232        this.getCallTreeConstraints = getCallTreeConstraints
233    }
234
235    getFilterData(getFilter: (v: FilterData) => void) {
236        this.getFilter = getFilter
237    }
238
239    getStatisticsTypeData(getStatisticsType: (v: any) => void) {
240        this.getStatisticsType = getStatisticsType
241    }
242
243    setSelectList(firstList: Array<any> | null | undefined = ["All Allocations", "Created & Existing", "Created & Destroyed"],
244                  secondList: Array<any> | null | undefined = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"],
245                  firstTitle = "Allocation Lifespan",secondTitle = "Allocation Type") {
246        if (!firstList && !secondList) return;
247        let sLE = this.shadowRoot?.querySelector("#load")
248        let html = ``;
249        if (firstList) {
250            html += `<lit-select default-value="" id="first-select" class="spacing" placeholder="please choose">`
251            if(firstTitle != ""){
252                html += `<lit-select-option value="${firstTitle}" disabled>${firstTitle}</lit-select-option>`
253            }
254            firstList!.forEach((a, b) => {
255                html += `<lit-select-option value="${b}">${a}</lit-select-option>`
256            })
257            html += `</lit-select>`
258        }
259        if (secondList) {
260            html += `<lit-select default-value="" id="second-select" class="spacing" placeholder="please choose">`
261            if(secondTitle != ""){
262                html += `<lit-select-option value="${secondTitle}" disabled>${secondTitle}</lit-select-option>`
263            }
264            secondList!.forEach((a, b) => {
265                html += `<lit-select-option value="${b}">${a}</lit-select-option>`
266            })
267            html += `</lit-select>`
268        }
269        if (!firstList) {
270            this.secondSelectEL!.outerHTML = html;
271        } else if (!secondList) {
272            this.firstSelectEL!.outerHTML = html;
273        } else {
274            sLE!.innerHTML = html;
275        }
276
277        this.firstSelectEL = this.shadowRoot?.querySelector("#first-select")
278        this.secondSelectEL = this.shadowRoot?.querySelector("#second-select")
279
280        this.firstSelectEL!.onchange = (e) => {
281            if (this.getFilter) {
282                this.getFilter(this.filterData("firstSelect"))
283            }
284        }
285        this.secondSelectEL!.onchange = (e) => {
286            if (this.getFilter) {
287                this.getFilter(this.filterData("secondSelect"))
288            }
289        }
290    }
291
292    initializeCallTree() {
293        let row = this.shadowRoot!.querySelectorAll(".tree-check");
294        row.forEach((e, idx) => {
295            let check = e.querySelector<LitCheckBox>("lit-check-box")
296            e.querySelector("div")!.onclick = (ev) => {
297                if (this.getCallTree) {
298                    if (idx == 0) {
299                        this.getCallTree({
300                            checks: [!check!.checked, row[1].querySelector<LitCheckBox>("lit-check-box")!.checked],
301                            value: idx
302                        });
303                    } else {
304                        this.getCallTree({
305                            checks: [row[0].querySelector<LitCheckBox>("lit-check-box")!.checked, !check!.checked],
306                            value: idx
307                        });
308                    }
309                }
310                check!.checked = !check!.checked;
311            }
312            check!.onchange = (ev: any) => {
313                if (this.getCallTree) {
314                    if (idx == 0) {
315                        this.getCallTree({
316                            checks: [ev.target.checked, row[1].querySelector<LitCheckBox>("lit-check-box")!.checked],
317                            value: idx
318                        });
319                    } else {
320                        this.getCallTree({
321                            checks: [row[0].querySelector<LitCheckBox>("lit-check-box")!.checked, ev.target.checked],
322                            value: idx
323                        });
324                    }
325                }
326            }
327        })
328    }
329
330    initializeTreeConstraints() {
331        let inputs = this.shadowRoot!.querySelectorAll<HTMLInputElement>(".constraints-input")
332        let check = this.shadowRoot!.querySelector<LitCheckBox>("#constraints-check")
333        check!.onchange = (ev: any) => {
334            inputs.forEach((e: any, idx) => {
335                if (inputs[idx].value == "") {
336                    inputs[idx].value = idx == 0 ? "0" : "∞"
337                }
338                ev.target.checked ? e.removeAttribute("disabled") : e.setAttribute("disabled", '')
339            })
340            if (this.getCallTreeConstraints) {
341                this.getCallTreeConstraints({
342                    checked: ev.target.checked,
343                    min: inputs[0].value,
344                    max: inputs[1].value
345                });
346            }
347        }
348        inputs.forEach((e, idx) => {
349            e.oninput = function () {
350                // @ts-ignore
351                this.value = this.value.replace(/\D/g, '');
352            }
353            e.addEventListener("keyup", (event: any) => {
354                event.stopPropagation();
355                if (event.keyCode == "13") {
356                    if (event?.target.value == "") {
357                        inputs[idx].value = idx == 0 ? "0" : "∞"
358                    }
359                    if (this.getCallTreeConstraints) {
360                        this.getCallTreeConstraints({
361                            checked: check!.checked,
362                            min: idx == 0 ? event?.target.value : inputs[0].value,
363                            max: idx == 1 ? event?.target.value : inputs[1].value
364                        });
365                    }
366                }
367            })
368        })
369    }
370
371    initializeMining() {
372        let html = ``;
373        this.cutList!.forEach((a, b) => {
374            html += `<div style="display: flex;padding: 4px 7px;" class="mining-checked" ${a.highlight ? "highlight" : ""}>
375                        <lit-check-box class="lit-check-box" not-close ${a.checked ? "checked" : ""} style="display: flex"></lit-check-box>
376                        <div id="title" title="${a.name}">${a.name}</div></div>`;
377        })
378
379        this.shadowRoot!.querySelector<HTMLDivElement>("#mining-row")!.innerHTML = html;
380
381        let row = this.shadowRoot!.querySelector("#mining-row")!.childNodes;
382        row!.forEach((e: any, idx) => {
383            e!.querySelector("#title")!.onclick = (ev: any) => {
384                if (e.getAttribute("highlight") == "") {
385                    e.removeAttribute("highlight")
386                    this.cutList![idx].highlight = false;
387                } else {
388                    e.setAttribute("highlight", "");
389                    this.cutList![idx].highlight = true;
390                }
391            }
392            // @ts-ignore
393            e!.querySelector<LitCheckBox>("lit-check-box")!.onchange = (ev) => {
394                // @ts-ignore
395                this.cutList[idx].checked = e!.querySelector<LitCheckBox>("lit-check-box")!.checked;
396                if (this.getMining) {
397                    this.getMining({type: "check", item: this.cutList![idx]});
398                }
399            }
400        })
401    }
402
403    initializeLibrary() {
404        let html = ``;
405        this.libraryList!.forEach((a, b) => {
406            html += `<div style="display: flex;padding: 4px 7px;" class="library-checked" ${a.highlight ? "highlight" : ""}>
407                        <lit-check-box class="lit-check-box" not-close ${a.checked ? "checked" : ""} style="display: flex"></lit-check-box>
408                        <div id="title" title="${a.name}">${a.name}</div></div>`;
409        })
410
411        this.shadowRoot!.querySelector<HTMLDivElement>("#library-row")!.innerHTML = html;
412
413        let row = this.shadowRoot!.querySelector("#library-row")!.childNodes;
414        row!.forEach((e: any, idx) => {
415            e!.querySelector("#title")!.onclick = (ev: any) => {
416                if (e.getAttribute("highlight") == "") {
417                    e.removeAttribute("highlight")
418                    this.libraryList![idx].highlight = false;
419                } else {
420                    e.setAttribute("highlight", "");
421                    this.libraryList![idx].highlight = true;
422                }
423            }
424
425            // @ts-ignore
426            e!.querySelector<LitCheckBox>("lit-check-box")!.onchange = (ev) => {
427                // @ts-ignore
428                this.libraryList[idx].checked = e!.querySelector<LitCheckBox>("lit-check-box")!.checked;
429                if (this.getLibrary) {
430                    this.getLibrary({type: "check", item: this.libraryList![idx]});
431                }
432            }
433        })
434    }
435
436    getDataMining(getMining: (v: MiningData) => void) {
437        this.getMining = getMining
438    }
439
440    getDataLibrary(getLibrary: (v: MiningData) => void) {
441        this.getLibrary = getLibrary
442    }
443
444    addDataMining(data: any, type: string) {
445        let list:Array<any> = (type=="symbol"?this.cutList:this.libraryList) ||[];
446        let idx = list!.findIndex((e) => e.name == data.name)
447        if (idx == -1) {
448            list!.push({type: type, name: data.name, checked: true, select: "1", data: data, highlight: false});
449        } else {
450            list![idx] = {type: type, name: data.name, checked: true, select: "1", data: data, highlight: false}
451        }
452        this.initializeMining();
453        this.initializeLibrary();
454        return idx;
455    }
456
457    getFilterTreeData() {
458        let row = this.shadowRoot!.querySelectorAll<LitCheckBox>(".tree-check lit-check-box");
459        let inputs = this.shadowRoot!.querySelectorAll<HTMLInputElement>(".constraints-input")
460        let check = this.shadowRoot!.querySelector<LitCheckBox>("#constraints-check")
461        let data = {
462            callTree: [row[0]!.checked, row[1]!.checked],
463            callTreeConstraints: {
464                checked: check!.checked,
465                inputs: [inputs[0].value == "" ? "0" : inputs[0].value, inputs[1].value == "" ? "∞" : inputs[1].value]
466            },
467            dataMining: this.cutList,
468            dataLibrary: this.libraryList,
469        }
470        return data;
471    }
472
473    initializeFilterTree(callTree: boolean = true, treeConstraints: boolean = true, mining: boolean = true) {
474        if (callTree) {
475            let row = this.shadowRoot!.querySelectorAll(".tree-check");
476            row.forEach((e, idx) => {
477                let check = e.querySelector<LitCheckBox>("lit-check-box")
478                check!.checked = false
479            })
480        }
481        if (treeConstraints) {
482            let inputs = this.shadowRoot!.querySelectorAll<HTMLInputElement>(".constraints-input")
483            if (inputs.length > 0) {
484                inputs[0].value = "0";
485                inputs[1].value = "∞";
486            }
487            let check = this.shadowRoot!.querySelector<LitCheckBox>("#constraints-check")
488            check!.checked = false
489        }
490        if (mining) {
491            this.cutList = [];
492            this.libraryList = [];
493            this.initializeMining();
494            this.initializeLibrary();
495        }
496    }
497
498    initHtml(): string {
499        return `
500        <style>
501        :host{
502            height: 30px;
503            background: var(--dark-background4,#F2F2F2);
504            border-top: 1px solid var(--dark-border1,#c9d0da);display: flex;align-items: center;z-index: 2;
505            margin-left: -10px;
506            width: calc(100% + 20px);
507        }
508
509        .chosen-single {
510            position: relative;
511            display: block;
512            overflow: hidden;
513            text-decoration: none;
514            white-space: nowrap;
515            height: 34px;
516            padding: 3px 6px;
517            font-size: 14px;
518            line-height: 1.42857143;
519            color: #555;
520            background-color: #fff;
521            background-image: none;
522            border: 1px solid #ccc;
523            border-radius: 4px;
524            transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
525            box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
526        }
527        .disabled{
528        color: rgba(0,0,0,0.4);
529        }
530        #filter-input{
531        background: var(--dark-background4,#FFFFFF);
532        border: 1px solid var(--dark-border,rgba(0,0,0,0.60));
533        color: var(--dark-color2,#000000);
534        border-radius: 8px;
535        width: 200px;
536        }
537        #filter-input:focus{
538            outline: none;
539            box-shadow: 1px 1px 1px var(--dark-color,#bebebe);
540        }
541        #filter-input::-webkit-input-placeholder {
542                color: var(--dark-color,#aab2bd);
543            }
544        .describe{
545        font-size: 0.8rem;
546        }
547
548        #mark{
549            border: 1px solid var(--bark-prompt,#999999);
550            border-radius: 1px;
551            background: var(--dark-background4,#F2F2F2);
552            color: var(--dark-color2,rgba(0,0,0,0.9));
553            transition: all 0.1s;
554        }
555        #mark:hover{
556            background: var(--dark-background1,#dfdfdf);
557        }
558        #mark:active{
559            background: var(--dark-background4,#F2F2F2);
560            transition: all 0.05s;
561        }
562        #first-select{
563        width: 200px;
564        }
565        #second-select{
566        width: 200px;
567        }
568        .spacing{
569        margin-left: 10px;
570        }
571        .max-spacing{
572        margin-left: 15px;
573        }
574
575        :host(:not([inputLeftText])) .left-text{
576            display: none;
577        }
578        :host(:not([input])) #filter-input{
579            display: none;
580        }
581        :host(:not([mark])) #mark{
582            display: none;
583        }
584        :host(:not([first])) #first-select{
585            display: none;
586        }
587        :host(:not([second])) #second-select{
588            display: none;
589        }
590        :host(:not([tree])) .tree{
591            display: none;
592        }
593        :host([disabledMining]) #data-mining{
594            display: none;
595        }
596        :host([disabledMining]) #data-library{
597            display: none;
598        }
599        :host(:not([icon])) #icon{
600            display: none;
601        }
602        #icon[name="statistics"]{
603            margin-left: 12px;
604        }
605
606        .constraints-input{
607            background: var(--dark-border,#ffffff);
608            color: var(--dark-color1,rgba(0,0,0,0.86));
609            border: 1px solid var(--dark-border,rgba(0,0,0,0.60));
610            border-radius: 10px;
611            width: 40px;
612            margin-left: 10px;
613            outline: none;
614        }
615        .constraints-input[disabled]{
616            background: var(--dark-background5,#ededed);
617        }
618        .mining-button{
619            opacity: 0.9;
620            font-size: 13px;
621            color: #0A59F7;
622            text-align: center;
623            line-height: 16px;
624            background: var(--dark-background3,#F4F3F4);
625            border: 1px solid var(--dark-background8,#F4F3F4);
626            border-radius: 16px;
627            padding: 2px 18px;
628        }
629        .library-button{
630            opacity: 0.9;
631            font-size: 13px;
632            color: #0A59F7;
633            text-align: center;
634            line-height: 16px;
635            background: var(--dark-background3,#F4F3F4);
636            border: 1px solid var(--dark-background8,#F4F3F4);
637            border-radius: 16px;
638            padding: 2px 18px;
639        }
640
641        #call-tree-popover[visible="true"] #call-tree{
642            color: #0A59F7;
643        }
644        #tree-constraints-popover[visible="true"] #tree-constraints{
645            color: #0A59F7;
646        }
647        #data-mining-popover[visible="true"] #data-mining{
648            color: #0A59F7;
649        }
650
651        .mining-checked[highlight]{
652            color: #FFFFFF;
653            background: #0C65D1;
654        }
655        #data-library-popover[visible="true"] #data-library{
656            color: #0A59F7;
657        }
658        .library-checked[highlight]{
659            color: #FFFFFF;
660            background: #0C65D1;
661        }
662        #title{
663            overflow: hidden;
664            white-space: nowrap;
665            text-overflow: ellipsis;
666            flex: 1;
667            text-align: left;
668        }
669        #mining-row{
670            background: var(--dark-background4,#F2F2F2);
671            border-radius: 2px;
672            height: 135px;
673            width: 250px;
674            overflow-y: auto;
675        }
676        #library-row{
677            background: var(--dark-background4,#F2F2F2);
678            border-radius: 2px;
679            height: 135px;
680            width: 250px;
681            overflow-y: auto;
682        }
683        .tree-check{
684            margin-bottom: 5px;
685            display: flex;
686            align-content: center;
687        }
688        .sort{
689            display: flex;
690            align-items: center;
691            cursor: pointer;
692        }
693        :host(:not([sort])) .sort{
694            display: none;
695        }
696</style>
697    <lit-icon name="statistics" class="spacing" id="icon" size="16"></lit-icon>
698    <span class="describe left-text spacing">Input Filter</span>
699    <input id="filter-input" class="spacing" placeholder="${this.inputPlaceholder}"/>
700    <button id="mark" class="spacing">Mark Snapshot</button>
701    <div id="load" style="display: flex">
702
703    </div>
704        <lit-popover placement="topLeft" class="popover" haveRadio="true" trigger="click" id="call-tree-popover">
705             <div slot="content">
706                 <div class="tree-check"><lit-check-box class="lit-check-box" not-close></lit-check-box><div>Invert</div></div>
707                 <div class="tree-check"><lit-check-box class="lit-check-box" not-close></lit-check-box><div>Hide System so</div></div>
708             </div>
709             <span class="describe tree max-spacing" id="call-tree">Options</span>
710        </lit-popover>
711        <lit-popover placement="topLeft" class="popover" haveRadio="true" trigger="click" id="tree-constraints-popover">
712             <div slot="content" style="display: flex; align-items: flex-end">
713                 <lit-check-box id="constraints-check" not-close></lit-check-box>
714                 <input class="constraints-input" disabled value="0" not-close/>
715                 <lit-popover placement="topLeft" class="popover" haveRadio="true" not-close>
716                     <div slot="content">
717                         <div style="font-size: 0.7rem">Constraints:Only enabled with data and while stopped;</div>
718                         <div style="font-size: 0.7rem">filters data to thresholds. </div>
719                     </div>
720                     <input class="constraints-input" disabled value="∞" not-close/>
721                  </lit-popover>
722             </div>
723             <span class="describe tree max-spacing" id="tree-constraints">Sample Count Filter</span>
724        </lit-popover>
725         <lit-popover placement="topLeft" class="popover" haveRadio="true" trigger="click" id="data-mining-popover">
726            <div slot="content">
727                 <div id="mining-row">
728
729                 </div>
730                 <div style="display: flex;justify-content: space-around; margin-top: 8px">
731                     <div class="mining-button">Reset</div>
732                 </div>
733            </div>
734            <span class="describe tree max-spacing" id="data-mining">Symbol Filter</span>
735        </lit-popover>
736        <lit-popover placement="topLeft" class="popover" haveRadio="true" trigger="click" id="data-library-popover">
737            <div slot="content">
738                 <div id="library-row">
739
740                 </div>
741                 <div style="display: flex;justify-content: space-around; margin-top: 8px">
742                     <div class="library-button">Reset</div>
743                 </div>
744            </div>
745            <span class="describe tree max-spacing" id="data-library">Library Filter</span>
746        </lit-popover>
747        <div class="sort">
748            <lit-icon name="swap" class="spacing" size="16"></lit-icon>
749            <div style="margin-left: 5px" class="statistics-name">Statistics by Thread</div>
750        </div>
751        `;
752    }
753}
754