• 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';
17import '../../../../base-ui/checkbox/LitCheckBox';
18import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox';
19import { TraceRow } from './TraceRow';
20import { SpSystemTrace } from '../../SpSystemTrace';
21import { LitSearch } from '../search/Search';
22import { TraceSheet } from './TraceSheet';
23import { CpuStruct } from '../../../database/ui-worker/cpu/ProcedureWorkerCPU';
24import { type BaseStruct } from '../../../bean/BaseStruct';
25import { LitIcon } from '../../../../base-ui/icon/LitIcon';
26import { TraceRowConfigHtml } from './TraceRowConfig.html';
27
28@element('trace-row-config')
29export class TraceRowConfig extends BaseElement {
30  static allTraceRowList: Array<TraceRow<BaseStruct>> = [];
31  private selectTypeList: Array<string> | undefined = [];
32  private subsystemSelectList: Array<SceneNode> | undefined = [];
33  private spSystemTrace: SpSystemTrace | null | undefined;
34  private sceneTable: HTMLDivElement | null | undefined;
35  private chartTable: HTMLDivElement | null | undefined;
36  private inputElement: HTMLInputElement | null | undefined;
37  private configTitle: HTMLDivElement | null | undefined;
38  private resetButton: HTMLButtonElement | null | undefined;
39  private traceRowList: NodeListOf<TraceRow<BaseStruct>> | undefined;
40  private exportFileIcon: LitIcon | null | undefined;
41  private switchButton: LitIcon | null | undefined;
42  private openFileIcon: LitIcon | null | undefined;
43  private openTempFile: HTMLInputElement | null | undefined;
44  private treeNodes: SubsystemNode[] = [];
45  private expandedNodeList: Set<number> = new Set();
46  private tempString: string | null = null;
47  private subSystemSearch: string | undefined;
48  private backTableHTML: string | undefined;
49  private otherRowNames: Array<SceneNode> = [];
50  private configList: string = '';
51  private defaultConfigList: string = '';
52  private sceneList = [
53    'FrameTimeline',
54    'AnimationEffect',
55    'AppStartup',
56    'TaskPool',
57    'HiSysEvent',
58    'EnergyEvent',
59    'Memory',
60    'ProcessMemory',
61    'ArkTs',
62    'NativeMemory',
63    'HiPerf',
64    'HiEBpf',
65  ];
66
67  static get observedAttributes(): string[] {
68    return ['mode'];
69  }
70
71  init(): void {
72    this.selectTypeList = [];
73    this.subsystemSelectList = [];
74    this.otherRowNames = [];
75    this.inputElement!.value = '';
76    this.exportFileIcon!.style.display = 'none';
77    this.openFileIcon!.style.display = 'none';
78    this.resetButton!.style.display = 'none';
79    this.configTitle!.innerHTML = 'Timeline Details';
80    this.spSystemTrace = this.parentElement!.querySelector<SpSystemTrace>('sp-system-trace');
81    this.traceRowList =
82      this.spSystemTrace!.shadowRoot?.querySelector('div[class=rows-pane]')!.querySelectorAll<TraceRow<BaseStruct>>(
83        "trace-row[row-parent-id='']"
84      );
85    TraceRowConfig.allTraceRowList.push(...this.traceRowList!);
86    this.refreshAllConfig(true, true);
87    // 鼠标移入该页面,隐藏泳道图tip
88    this.onmouseenter = (): void => {
89      this.spSystemTrace!.tipEL!.style.display = 'none';
90      this.spSystemTrace!.hoverStructNull();
91      this.spSystemTrace!.refreshCanvas(true);
92    };
93  }
94
95  private refreshAllConfig(
96    isRefreshTopTable: boolean = false,
97    isRefreshBottomTable: boolean = false,
98    isSubSysConfig: boolean = false
99  ): void {
100    let allowSceneList: Array<string> = [];
101    this.selectTypeList = [];
102    this.subsystemSelectList = [];
103    this.otherRowNames = [];
104    this.switchButton!.title = 'Show subSystem template';
105    let topPanel = new DocumentFragment();
106    let bottomPanel = new DocumentFragment();
107    this.traceRowList!.forEach((traceRow: TraceRow<BaseStruct>) => {
108      traceRow.setAttribute('scene', '');
109      this.otherRowNames.push({
110        nodeName: traceRow.name,
111        scene: [...traceRow.templateType],
112      });
113      this.subsystemSelectList!.push({
114        nodeName: traceRow.name,
115        scene: [...traceRow.templateType],
116      });
117      if (isRefreshTopTable) {
118        this.sceneTable!.innerHTML = '';
119        if (traceRow.templateType.size > 0) {
120          traceRow.templateType.forEach((type) => {
121            if (this.sceneList.indexOf(type) >= 0 && allowSceneList.indexOf(type) < 0) {
122              allowSceneList.push(type);
123              this.initConfigSceneTable(type, topPanel);
124            }
125          });
126        }
127      }
128      if (isRefreshBottomTable) {
129        if (isSubSysConfig) {
130          this.backTableHTML = '';
131          this.chartTable!.innerHTML = '';
132        } else {
133          this.removeAttribute('temp_config');
134          this.backTableHTML = this.chartTable!.innerHTML;
135          this.chartTable!.innerHTML = '';
136          this.initConfigChartTable(traceRow, bottomPanel);
137        }
138      }
139    });
140    this.sceneTable?.appendChild(topPanel);
141    this.chartTable?.appendChild(bottomPanel);
142  }
143
144  initConfigSceneTable(item: string, topPanel: DocumentFragment): void {
145    let spliceIndex = 1;
146    let div = document.createElement('div');
147    div.className = 'scene-option-div';
148    div.textContent = item;
149    let optionCheckBox: LitCheckBox = new LitCheckBox();
150    optionCheckBox.checked = false;
151    optionCheckBox.style.justifySelf = 'center';
152    optionCheckBox.style.height = '100%';
153    optionCheckBox.title = item;
154    optionCheckBox.addEventListener('change', () => {
155      this.subsystemSelectList = [];
156      this.clearLines(optionCheckBox.title);
157      if (optionCheckBox.checked) {
158        this.selectTypeList!.push(item);
159      } else {
160        if (this.selectTypeList!.length > 0) {
161          let indexNum = this.selectTypeList!.indexOf(item);
162          this.selectTypeList!.splice(indexNum, spliceIndex);
163        }
164      }
165      this.resetChartOption();
166      this.resetChartTable();
167    });
168    let htmlDivElement = document.createElement('div');
169    htmlDivElement.style.display = 'grid';
170    htmlDivElement.style.gridTemplateColumns = '1fr 1fr';
171    htmlDivElement.appendChild(div);
172    htmlDivElement.appendChild(optionCheckBox);
173    topPanel.appendChild(htmlDivElement);
174  }
175
176  clearLines(type: string): void {
177    if (type === 'FrameTimeline' || type === 'AppStartup') {
178      this.spSystemTrace?.removeLinkLinesByBusinessType('janks');
179    } else if (type === 'Task Pool') {
180      this.spSystemTrace?.removeLinkLinesByBusinessType('task');
181    } else if (type === 'func') {
182      this.spSystemTrace?.removeLinkLinesByBusinessType('distributed');
183    }
184  }
185
186  initConfigChartTable(row: TraceRow<BaseStruct>, bottomPanel: DocumentFragment): void {
187    let templateType = '';
188    if (row.templateType.size > 0) {
189      templateType = [...row.templateType].reduce((pre, cur) => `${pre}:${cur}`);
190    }
191    let div = document.createElement('div');
192    div.className = 'chart-option-div chart-item';
193    div.textContent = row.name;
194    div.title = row.name;
195    div.setAttribute('search_text', row.name);
196    let optionCheckBox: LitCheckBox = new LitCheckBox();
197    optionCheckBox.checked = true;
198    optionCheckBox.className = 'chart-config-check chart-item';
199    optionCheckBox.style.height = '100%';
200    optionCheckBox.style.justifySelf = 'center';
201    optionCheckBox.title = templateType;
202    optionCheckBox.setAttribute('search_text', row.name);
203    optionCheckBox.addEventListener('change', () => {
204      if (row.folder) {
205        TraceRowConfig.allTraceRowList.forEach((chartRow): void => {
206          let upParentRow = chartRow;
207          while (upParentRow.hasParentRowEl) {
208            if (!upParentRow.parentRowEl) {
209              break;
210            } // @ts-ignore
211            upParentRow = upParentRow.parentRowEl;
212          }
213          if (upParentRow === row) {
214            if (optionCheckBox.checked) {
215              chartRow.rowHidden = false;
216              chartRow.setAttribute('scene', '');
217            } else {
218              row.expansion = false;
219              chartRow.removeAttribute('scene');
220              chartRow.rowHidden = true;
221            }
222          }
223        });
224      }
225      if (optionCheckBox.checked) {
226        row.rowHidden = false;
227        row.setAttribute('scene', '');
228      } else {
229        row.removeAttribute('scene');
230        row.rowHidden = true;
231      }
232      this.refreshSystemPanel();
233    });
234    bottomPanel.append(...[div, optionCheckBox]);
235  }
236
237  resetChartOption(): void {
238    this.shadowRoot!.querySelectorAll<LitCheckBox>('.chart-item').forEach((litCheckBox: LitCheckBox) => {
239      let isShowCheck: boolean = false;
240      if (this.selectTypeList!.length === 0) {
241        isShowCheck = true;
242      } else {
243        if (litCheckBox.title !== '') {
244          let divTemplateTypeList = litCheckBox.title.split(':');
245          for (let index = 0; index < divTemplateTypeList.length; index++) {
246            let type = divTemplateTypeList[index];
247            if (this.selectTypeList!.indexOf(type) >= 0) {
248              isShowCheck = true;
249              break;
250            }
251          }
252        }
253      }
254      litCheckBox.checked = isShowCheck;
255    });
256    if (this.hasAttribute('temp_config')) {
257      this.refreshNodes(this.treeNodes);
258      this.refreshSelectList(this.treeNodes);
259      this.refreshTable();
260    }
261  }
262
263  refreshSelectList(nodes: SubsystemNode[]): void {
264    nodes.forEach((item) => {
265      if (item.depth === 3) {
266        if (item.isCheck) {
267          this.subsystemSelectList!.push({
268            nodeName: item.nodeName,
269            scene: item.scene,
270          });
271        }
272      }
273      if (item.children.length > 0) {
274        this.refreshSelectList(item.children);
275      }
276    });
277  }
278
279  resetChartTable(): void {
280    if (this.traceRowList && this.traceRowList.length > 0) {
281      this.traceRowList.forEach((traceRow: TraceRow<BaseStruct>) => {
282        let isShowRow: boolean = false;
283        if (this.selectTypeList!.length === 0) {
284          traceRow.rowHidden = false;
285          traceRow.setAttribute('scene', ''); // @ts-ignore
286          this.refreshChildRow(traceRow.childrenList, true);
287        } else {
288          let templateTypeList = [...traceRow.templateType];
289          isShowRow = templateTypeList.some((type) => this.selectTypeList!.includes(type));
290          traceRow.expansion = false;
291          if (isShowRow) {
292            if (traceRow.templateType.size > 0) {
293              traceRow.rowHidden = false;
294              traceRow.setAttribute('scene', '');
295              if (traceRow.childrenList && traceRow.childrenList.length > 0) {
296                // @ts-ignore
297                this.refreshChildRow(traceRow.childrenList, isShowRow);
298              }
299            }
300          } else {
301            traceRow.removeAttribute('scene');
302            traceRow.rowHidden = true; // @ts-ignore
303            this.refreshChildRow(traceRow.childrenList);
304          }
305        }
306      });
307      this.handleCollectRow();
308    }
309    this.refreshSystemPanel();
310  }
311
312  private handleCollectRow(): void {
313    this.spSystemTrace?.collectRows.forEach((favoriteRow) => {
314      let isShowRow: boolean = false;
315      if (this.selectTypeList!.length === 0) {
316        favoriteRow.rowHidden = false;
317        favoriteRow.setAttribute('scene', '');
318      } else {
319        if (favoriteRow.parentRowEl) {
320          favoriteRow.parentRowEl.expansion = false;
321          let favoriteList = [...favoriteRow.parentRowEl!.templateType];
322          isShowRow = favoriteList.some((type) => this.selectTypeList!.includes(type));
323        } else {
324          let typeList = [...favoriteRow.templateType];
325          isShowRow = typeList.some((type) => this.selectTypeList!.includes(type));
326        }
327        if (isShowRow) {
328          favoriteRow.rowHidden = false;
329          favoriteRow.setAttribute('scene', '');
330        } else {
331          favoriteRow.removeAttribute('scene');
332          favoriteRow.rowHidden = true;
333        }
334      }
335    });
336  }
337
338  refreshNodes(nodes: SubsystemNode[]): void {
339    if (this.selectTypeList?.length !== 0) {
340      for (let index = 0; index < nodes.length; index++) {
341        let item = nodes[index];
342        let exists = false;
343        item.scene?.forEach((sceneItem) => {
344          if (this.selectTypeList!.some((elem) => elem === sceneItem)) {
345            exists = true;
346            return;
347          }
348        });
349        if (exists) {
350          item.isCheck = true;
351        } else {
352          item.isCheck = false;
353        }
354        this.refreshNodes(item.children);
355      }
356    } else {
357      for (let index = 0; index < nodes.length; index++) {
358        let item = nodes[index];
359        item.isCheck = true;
360        this.refreshNodes(item.children);
361      }
362    }
363  }
364
365  refreshChildRow(childRows: Array<TraceRow<BaseStruct>>, isShowScene: boolean = false): void {
366    childRows.forEach((row) => {
367      if (isShowScene) {
368        row.setAttribute('scene', '');
369        if (row.childrenList && row.childrenList.length > 0) {
370          // @ts-ignore
371          this.refreshChildRow(row.childrenList, isShowScene);
372        }
373        row.expansion = false;
374      } else {
375        row.removeAttribute('scene');
376        row.rowHidden = true;
377        if (row.childrenList && row.childrenList.length > 0) {
378          // @ts-ignore
379          this.refreshChildRow(row.childrenList);
380        }
381      }
382    });
383  }
384
385  refreshSystemPanel(): void {
386    this.clearSearchAndFlag();
387    this.spSystemTrace!.rowsPaneEL!.scroll({
388      top: 0 - this.spSystemTrace!.canvasPanel!.offsetHeight,
389      left: 0,
390      behavior: 'smooth',
391    });
392    this.spSystemTrace!.refreshFavoriteCanvas();
393    this.spSystemTrace!.refreshCanvas(true);
394  }
395
396  clearSearchAndFlag(): void {
397    let traceSheet = this.spSystemTrace!.shadowRoot?.querySelector('.trace-sheet') as TraceSheet;
398    if (traceSheet) {
399      traceSheet!.setMode('hidden');
400    }
401    let search = document.querySelector('sp-application')!.shadowRoot?.querySelector('#lit-search') as LitSearch;
402    if (search) {
403      search.clear();
404    }
405    let highlightRow = this.spSystemTrace!.shadowRoot?.querySelector<TraceRow<BaseStruct>>('trace-row[highlight]');
406    if (highlightRow) {
407      highlightRow.highlight = false;
408    }
409    this.spSystemTrace!.timerShaftEL?.removeTriangle('inverted');
410    CpuStruct.wakeupBean = undefined;
411    this.spSystemTrace!.hoverFlag = undefined;
412    this.spSystemTrace!.selectFlag = undefined;
413  }
414
415  initElements(): void {
416    this.sceneTable = this.shadowRoot!.querySelector<HTMLDivElement>('#scene-select');
417    this.chartTable = this.shadowRoot!.querySelector<HTMLDivElement>('#chart-select');
418    this.inputElement = this.shadowRoot!.querySelector('input');
419    this.openTempFile = this.shadowRoot?.querySelector<HTMLInputElement>('#open-temp-file');
420    this.exportFileIcon = this.shadowRoot?.querySelector<LitIcon>('#export-file-icon');
421    this.switchButton = this.shadowRoot?.querySelector<LitIcon>('#switch-button');
422    this.openFileIcon = this.shadowRoot?.querySelector<LitIcon>('#open-file-icon');
423    this.configTitle = this.shadowRoot?.querySelector<HTMLDivElement>('#config_title');
424    this.resetButton = this.shadowRoot?.querySelector<HTMLButtonElement>('#resetTemplate');
425    this.initSwitchClickListener();
426    this.openFileIcon!.addEventListener('click', () => {
427      this.openTempFile!.value = '';
428      this.openTempFile?.click();
429    });
430    this.resetButton!.addEventListener('click', () => {
431      this.loadTempConfig(this.defaultConfigList);
432      this.resetChartTable();
433    });
434  }
435
436  private initSwitchClickListener(): void {
437    let jsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port
438      }/application/trace/config/custom_temp_config.json`;
439    this.switchButton!.addEventListener('click', () => {
440      if (this.switchButton!.title === 'Show charts template') {
441        this.switchButton!.title = 'Show subSystem template';
442        this.refreshAllConfig(true, true);
443        this.resetChartTable();
444        this.openFileIcon!.style.display = 'none';
445        this.exportFileIcon!.style.display = 'none';
446        this.configTitle!.innerHTML = 'Timeline Details';
447        this.resetButton!.style.display = 'none';
448      } else {
449        this.switchButton!.title = 'Show charts template';
450        this.openFileIcon!.style.display = 'block';
451        this.exportFileIcon!.style.display = 'block';
452        this.resetButton!.style.display = 'block';
453        this.configTitle!.innerHTML = 'SubSystem Template';
454        if (this.configList) {
455          this.loadTempConfig(this.configList);
456        } else {
457          if (this.defaultConfigList === '') {
458            fetch(jsonUrl)
459              .then((res) => {
460                if (res.ok) {
461                  res.text().then((text) => {
462                    this.defaultConfigList = text;
463                    this.loadTempConfig(this.defaultConfigList);
464                  });
465                }
466              })
467            ['catch']((err) => {
468              console.log(err);
469            });
470          } else {
471            this.loadTempConfig(this.defaultConfigList);
472          }
473        }
474        this.resetChartTable();
475      }
476    });
477  }
478
479  private filterSearch(): void {
480    this.shadowRoot!.querySelectorAll<HTMLElement>('.temp-chart-item').forEach((subSystemOption: HTMLElement) => {
481      this.subSystemSearch = subSystemOption.getAttribute('search_text') || '';
482      if (this.subSystemSearch!.toLowerCase().indexOf(this.inputElement!.value.toLowerCase()) < 0) {
483        subSystemOption.style.display = 'none';
484      } else {
485        subSystemOption.style.display = 'grid';
486      }
487    });
488  }
489
490  connectedCallback(): void {
491    this.inputElement?.addEventListener('keyup', () => {
492      this.shadowRoot!.querySelectorAll<HTMLElement>('.chart-item').forEach((elementOption: HTMLElement) => {
493        let searchText = elementOption.getAttribute('search_text') || '';
494        if (searchText!.toLowerCase().indexOf(this.inputElement!.value.toLowerCase()) < 0) {
495          elementOption.style.display = 'none';
496        } else {
497          elementOption.style.display = 'block';
498        }
499      });
500      this.filterSearch();
501    });
502    this.openTempFile!.addEventListener('change', (event) => {
503      let that = this;
504      let fileList = (event.target as HTMLInputElement).files;
505      if (fileList && fileList.length > 0) {
506        let file = fileList[0];
507        if (file) {
508          let reader = new FileReader();
509          reader.onload = (): void => {
510            that.loadTempConfig(reader.result as string);
511          };
512          reader.readAsText(file);
513        }
514      }
515    });
516    this.exportFileIcon!.addEventListener('click', () => {
517      this.exportConfig();
518    });
519  }
520
521  exportConfig(): void {
522    let a = document.createElement('a');
523    let encoder = new TextEncoder();
524    let tempBuffer = encoder.encode(this.tempString!);
525    a.href = URL.createObjectURL(new Blob([tempBuffer]));
526    a.download = 'custom_temp_config';
527    a.click();
528    window.URL.revokeObjectURL(a.href);
529  }
530
531  loadTempConfig(text: string): void {
532    this.selectTypeList = [];
533    this.inputElement!.value = '';
534    this.backTableHTML = this.chartTable?.innerHTML;
535    let configJson;
536    let isTrulyJson = false;
537    try {
538      configJson = JSON.parse(text);
539      let subsystemsKey: string = 'subsystems';
540      if (configJson[subsystemsKey]) {
541        isTrulyJson = true;
542        this.tempString = text;
543        this.openFileIcon!.style.display = 'block';
544      }
545    } catch (e) {
546      console.log(e);
547    }
548    if (!isTrulyJson) {
549      return;
550    }
551    let id = 0;
552    try {
553      this.treeNodes = this.buildSubSystemTreeData(id, configJson);
554    } catch (e) {
555      this.loadTempConfig(this.configList);
556      return;
557    }
558    this.configList = text;
559    this.buildTempOtherList(id);
560    this.setAttribute('temp_config', '');
561    this.expandedNodeList.clear();
562    this.refreshTable();
563  }
564
565  // 构建节点关系
566  private buildSubSystemTreeData(id: number, configJson: unknown): SubsystemNode[] {
567    let subsystemsKey: string = 'subsystems'; // @ts-ignore
568    let keys = Object.keys(configJson);
569    if (keys.indexOf(subsystemsKey) < 0) {
570      return [];
571    }
572    let subSystems: SubsystemNode[] = []; // @ts-ignore
573    let subsystemsData = configJson[subsystemsKey];
574    this.initOtherRowNames();
575    let subsystemList = [];
576    for (let subIndex = 0; subIndex < subsystemsData.length; subIndex++) {
577      let currentSystemData = subsystemsData[subIndex];
578      if (
579        !currentSystemData.subsystem || currentSystemData.subsystem === '' ||
580        subsystemList.indexOf(currentSystemData.subsystem) > -1 ||
581        Array.isArray(currentSystemData.subsystem)
582      ) {
583        continue;
584      }
585      let currentSubName = currentSystemData.subsystem;
586      subsystemList.push(currentSystemData.subsystem);
587      id++;
588      let subsystemStruct: SubsystemNode = {
589        id: id,
590        nodeName: currentSubName,
591        children: [],
592        depth: 1,
593        isCheck: true,
594        scene: [],
595      };
596      if (subSystems.indexOf(subsystemStruct) < 0) {
597        let currentCompDates = currentSystemData.components;
598        if (!currentCompDates || !Array.isArray(currentCompDates)) {
599          continue;
600        }
601        for (let compIndex = 0; compIndex < currentCompDates.length; compIndex++) {
602          let currentCompDate = currentCompDates[compIndex];
603          if (!currentCompDate.component || currentCompDate.component === '' || !currentCompDate.charts) {
604            continue;
605          }
606          id = this.setSubsystemComp(currentCompDate, id, subsystemStruct);
607        }
608        subSystems.push(subsystemStruct);
609      }
610    }
611    return subSystems;
612  }
613
614  private initOtherRowNames(): void {
615    if (this.traceRowList) {
616      this.otherRowNames = [];
617      for (let index = 0; index < this.traceRowList.length; index++) {
618        let item = this.traceRowList[index];
619        this.otherRowNames.push({
620          nodeName: item.name,
621          scene: [...item.templateType],
622        });
623      }
624    }
625  }
626
627  private setSubsystemComp(currentCompDate: unknown, id: number, subsystemStruct: SubsystemNode): number {
628    // @ts-ignore
629    let currentCompName = currentCompDate.component; // @ts-ignore
630    let currentChartDates = currentCompDate.charts; // @ts-ignore
631    id++;
632    let componentStruct: SubsystemNode = {
633      id: id,
634      parent: subsystemStruct,
635      nodeName: currentCompName,
636      children: [],
637      depth: 2,
638      isCheck: true,
639      scene: [],
640    };
641    for (let chartIndex = 0; chartIndex < currentChartDates.length; chartIndex++) {
642      let currentChartDate = currentChartDates[chartIndex];
643      if (
644        (!currentChartDate.chartName && !currentChartDate.chartId) ||
645        Array.isArray(currentChartDate.chartName)
646      ) {
647        continue;
648      }
649      let currentChartName = `${currentChartDate.chartName}`;
650      let currentChartId = currentChartDate.chartId;
651      let findChartNames: Array<string> | undefined = [];
652      let scene: string[] = [];
653      this.setSubsystemChart(currentChartName, currentChartId, scene, findChartNames);
654      findChartNames.forEach((currentChartName) => {
655        id++;
656        let chartStruct: SubsystemNode = {
657          id: id,
658          parent: componentStruct,
659          nodeName: currentChartName,
660          children: [],
661          depth: 3,
662          isCheck: true,
663          scene: scene,
664        };
665        if (componentStruct.children.indexOf(chartStruct) < 0) {
666          let rowNumber = this.otherRowNames.findIndex((row) => row.nodeName === chartStruct.nodeName);
667          if (rowNumber >= 0) {
668            this.otherRowNames.splice(rowNumber, 1);
669          }
670          componentStruct.children.push(chartStruct);
671        }
672      });
673    }
674    if (subsystemStruct.children.indexOf(componentStruct) < 0) {
675      subsystemStruct.children.push(componentStruct);
676    }
677    return id;
678  }
679
680  private setSubsystemChart(
681    currentChartName: string,
682    currentChartId: string,
683    scene: Array<string>,
684    findChartNames: Array<string>
685  ): void {
686    if (this.traceRowList) {
687      for (let index = 0; index < this.traceRowList.length; index++) {
688        let item = this.traceRowList[index];
689        let chartId = '';
690        let name = item.name;
691        let pattern = / (\d+)$/;
692        let match = item.name.match(pattern);
693        if (match) {
694          chartId = match[0].trim();
695          name = item.name.split(match[0])[0];
696          if (name !== 'Cpu') {
697            if (
698              (currentChartName !== undefined &&
699                currentChartName !== '' &&
700                name.toLowerCase().endsWith(currentChartName.toLowerCase())) ||
701              currentChartId === chartId
702            ) {
703              scene.push(...item.templateType);
704              findChartNames.push(item.name);
705            }
706          } else {
707            if (
708              currentChartName !== undefined &&
709              currentChartName !== '' &&
710              name.toLowerCase().endsWith(currentChartName.toLowerCase())
711            ) {
712              scene.push(...item.templateType);
713              findChartNames.push(item.name);
714            }
715          }
716        } else {
717          if (
718            currentChartName !== undefined &&
719            currentChartName !== '' &&
720            name.toLowerCase().endsWith(currentChartName.toLowerCase())
721          ) {
722            scene.push(...item.templateType);
723            findChartNames.push(item.name);
724          }
725        }
726      }
727    }
728  }
729
730  refreshTable(): void {
731    this.chartTable!.innerHTML = '';
732    for (let index = 0; index < this.treeNodes.length; index++) {
733      this.buildSubsystem(this.treeNodes[index]);
734    }
735    this.filterSearch();
736  }
737
738  buildSubsystem(subsystemNode: SubsystemNode): void {
739    let subsystemDiv = document.createElement('div');
740    subsystemDiv.className = 'layout temp-chart-item';
741    subsystemDiv.title = subsystemNode.nodeName!;
742    subsystemDiv.setAttribute('search_text', subsystemNode.nodeName!);
743    if (subsystemNode.scene) {
744      subsystemDiv.title = subsystemNode.scene.toString();
745    }
746    if (subsystemNode.depth !== 3) {
747      let container = document.createElement('div');
748      container.style.display = 'flex';
749      container.style.marginLeft = `${subsystemNode.depth * 25}px`;
750      container.style.alignItems = 'center';
751      let expandIcon = document.createElement('lit-icon') as LitIcon;
752      expandIcon.name = 'caret-down';
753      expandIcon.className = 'expand-icon';
754      if (this.expandedNodeList.has(subsystemNode.id)) {
755        expandIcon.setAttribute('expansion', '');
756      } else {
757        expandIcon.removeAttribute('expansion');
758      }
759      expandIcon.addEventListener('click', () => {
760        this.changeNode(subsystemNode.id);
761        this.refreshTable();
762      });
763      let componentDiv = document.createElement('div');
764      componentDiv.className = 'subsystem-div';
765      componentDiv.textContent = subsystemNode.nodeName!;
766      container.appendChild(expandIcon);
767      container.appendChild(componentDiv);
768      subsystemDiv.appendChild(container);
769    } else {
770      let chartDiv = document.createElement('div');
771      chartDiv.className = 'chart-option';
772      chartDiv.textContent = subsystemNode.nodeName!;
773      subsystemDiv.appendChild(chartDiv);
774    }
775    let configCheckBox: LitCheckBox = new LitCheckBox();
776    configCheckBox.className = 'scene-check-box temp-chart-item';
777    configCheckBox.setAttribute('search_text', subsystemNode.nodeName!);
778    this.buildCheckBox(configCheckBox, subsystemNode);
779    subsystemDiv.appendChild(configCheckBox);
780    this.chartTable?.appendChild(subsystemDiv);
781    if (subsystemNode.children && this.expandedNodeList.has(subsystemNode.id)) {
782      subsystemNode.children.forEach((item) => {
783        this.buildSubsystem(item);
784      });
785    }
786  }
787
788  private buildCheckBox(configCheckBox: LitCheckBox, subsystemNode: SubsystemNode): void {
789    if (subsystemNode.scene) {
790      configCheckBox.title = subsystemNode.scene.toString();
791    }
792    configCheckBox.checked = subsystemNode.isCheck!;
793    configCheckBox.addEventListener('change', () => {
794      this.spSystemTrace?.removeLinkLinesByBusinessType('janks');
795      this.spSystemTrace?.removeLinkLinesByBusinessType('task');
796      this.setChildIsSelect(subsystemNode, configCheckBox);
797      this.setParentSelect(subsystemNode, configCheckBox.checked);
798      this.refreshTable();
799      this.displayRow(subsystemNode, configCheckBox);
800      // 收藏后的泳道的展示或者隐藏
801      this.spSystemTrace?.collectRows.forEach((subsystemFavorite) => {
802        let isShowRow: boolean = false;
803        let favoriteName = '';
804        if (this.subsystemSelectList!.length === 0) {
805          subsystemFavorite.removeAttribute('scene');
806          subsystemFavorite.rowHidden = true;
807        } else {
808          if (subsystemFavorite.parentRowEl) {
809            subsystemFavorite.parentRowEl.expansion = false;
810            favoriteName = subsystemFavorite.parentRowEl!.name;
811            // 三级泳道判断
812            if (subsystemFavorite.parentRowEl.parentRowEl) {
813              subsystemFavorite.parentRowEl.parentRowEl.expansion = false;
814              favoriteName = subsystemFavorite.parentRowEl.parentRowEl.name;
815            }
816            for (let i = 0; i < this.subsystemSelectList!.length; i++) {
817              if (this.subsystemSelectList![i].nodeName === favoriteName) {
818                isShowRow = true;
819                break;
820              }
821            }
822          } else {
823            favoriteName = subsystemFavorite.name;
824            for (let i = 0; i < this.subsystemSelectList!.length; i++) {
825              if (this.subsystemSelectList![i].nodeName === favoriteName) {
826                isShowRow = true;
827                break;
828              }
829            }
830          }
831          if (isShowRow) {
832            subsystemFavorite.rowHidden = false;
833            subsystemFavorite.setAttribute('scene', '');
834          } else {
835            subsystemFavorite.removeAttribute('scene');
836            subsystemFavorite.rowHidden = true;
837          }
838        }
839      });
840      this.refreshSystemPanel();
841    });
842  }
843
844  private buildTempOtherList(id: number): void {
845    let otherRootNode: SubsystemNode = {
846      children: [],
847      depth: 1,
848      id: id,
849      nodeName: 'other',
850      isCheck: true,
851      scene: [],
852    };
853    for (let index = 0; index < this.otherRowNames!.length; index++) {
854      otherRootNode.children.push({
855        children: [],
856        depth: 3,
857        id: id++,
858        nodeName: this.otherRowNames![index].nodeName,
859        isCheck: true,
860        parent: otherRootNode,
861        scene: this.otherRowNames![index].scene,
862      });
863    }
864    this.treeNodes.push(otherRootNode);
865  }
866
867  private setChildIsSelect(node: SubsystemNode, configCheckBox: LitCheckBox): void {
868    node.isCheck = configCheckBox.checked;
869    if (node.children.length > 0) {
870      node.children.forEach((childItem) => {
871        this.displayRow(childItem, configCheckBox);
872        this.setChildIsSelect(childItem, configCheckBox);
873      });
874    }
875  }
876
877  private displayRow(node: SubsystemNode, configCheckBox: LitCheckBox): void {
878    if (node.depth === 3) {
879      let chartNumber = this.subsystemSelectList?.findIndex((item) => item.nodeName === node.nodeName!);
880      if (configCheckBox.checked) {
881        if (chartNumber === -1) {
882          this.subsystemSelectList?.push({
883            nodeName: node.nodeName!,
884            scene: configCheckBox.title.split(','),
885          });
886        }
887      } else {
888        if (chartNumber !== undefined && chartNumber !== null) {
889          this.subsystemSelectList?.splice(chartNumber, 1);
890        }
891      }
892      this.traceRowList?.forEach((item) => {
893        if (item.name === node.nodeName) {
894          if (configCheckBox.checked) {
895            item.setAttribute('scene', '');
896            item.removeAttribute('row-hidden');
897            item.childrenList.forEach(v => {
898              if (v.hasAttribute('row-hidden')) {
899                v.setAttribute('scene', '');
900                v.removeAttribute('row-hidden');
901              }
902            });
903          } else {
904            item.expansion = false;
905            item.removeAttribute('scene');
906            item.setAttribute('row-hidden', '');
907          }
908        }
909      });
910    }
911  }
912
913  private setParentSelect(node: SubsystemNode, isSelect: boolean): void {
914    if (node.parent) {
915      if (isSelect) {
916        node.parent.isCheck = isSelect;
917      } else {
918        let isParentCheck = false;
919        for (let index = 0; index < node.parent!.children.length; index++) {
920          let childItem = node.parent!.children[index];
921          if (childItem.isCheck) {
922            isParentCheck = true;
923            break;
924          }
925        }
926        node.parent.isCheck = isParentCheck;
927      }
928      if (node.parent.parent) {
929        this.setParentSelect(node.parent, isSelect);
930      }
931    }
932  }
933
934  private changeNode(currentNode: number): void {
935    if (this.expandedNodeList.has(currentNode)) {
936      this.expandedNodeList['delete'](currentNode);
937    } else {
938      this.expandedNodeList.add(currentNode);
939    }
940    this.refreshTable();
941  }
942
943  initHtml(): string {
944    return TraceRowConfigHtml;
945  }
946
947  attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
948    if (name === 'mode' && newValue === '') {
949      this.init();
950    }
951  }
952}
953
954export interface SubsystemNode {
955  id: number;
956  parent?: SubsystemNode;
957  nodeName: string | undefined | null;
958  children: SubsystemNode[];
959  depth: number;
960  isCheck?: boolean;
961  scene?: string[];
962}
963
964export interface SceneNode {
965  nodeName: string | undefined | null;
966  scene?: string[];
967}
968