• 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 { SelectionParam } from '../../../../bean/BoxSelection';
18import { LitIcon } from '../../../../../base-ui/icon/LitIcon';
19import { HiSysEventStruct } from '../../../../database/ui-worker/ProcedureWorkerHiSysEvent';
20import { LitTable } from '../../../../../base-ui/table/lit-table';
21import { ColorUtils } from '../../base/ColorUtils';
22import { TabPaneHiSysEventSummaryHtml } from './TabPaneHiSysEventSummary.html';
23import { NUM_30, NUM_40 } from '../../../../bean/NumBean';
24import { queryHiSysEventTabData } from '../../../../database/sql/Perf.sql';
25
26@element('tab-hi-sysevent-summary')
27export class TabPaneHiSysEventSummary extends BaseElement {
28  private summarySource: Array<HiSysEventStruct> = [];
29  private eventSummaryTable: HTMLDivElement | undefined | null;
30  private summaryTable: LitTable | undefined | null;
31  private eventTreeNodes: HiSysEventTreeNode[] = [];
32  private expansionDiv: HTMLDivElement | undefined | null;
33  private expansionUpIcon: LitIcon | undefined | null;
34  private expansionDownIcon: LitIcon | undefined | null;
35  private expandedNodeList: Set<number> = new Set();
36  private selectTreeDepth: number = 0;
37  private currentSelection: SelectionParam | undefined;
38
39  set data(systemEventParam: SelectionParam) {
40    if (systemEventParam === this.currentSelection) {
41      return;
42    }
43    this.summarySource = [];
44    this.expandedNodeList.clear();
45    this.expansionUpIcon!.name = 'up';
46    this.expansionDownIcon!.name = 'down';
47    this.eventSummaryTable!.innerHTML = '';
48    this.summaryTable!.recycleDataSource = [];
49    queryHiSysEventTabData(systemEventParam.leftNs, systemEventParam.rightNs).then((res) => {
50      this.currentSelection = systemEventParam;
51      systemEventParam.sysAllEventsData = res;
52      this.summarySource = systemEventParam.sysAllEventsData;
53      this.summaryTable!.recycleDataSource = res;
54      this.refreshRowNodeTable();
55    });
56    if (this.summarySource?.length !== 0 && systemEventParam) {
57      this.refreshRowNodeTable();
58    }
59  }
60
61  initElements(): void {
62    this.eventSummaryTable = this.shadowRoot?.querySelector<HTMLDivElement>('#tab-summary');
63    this.summaryTable = this.shadowRoot?.querySelector<LitTable>('#tb-event-summary');
64    this.expansionDiv = this.shadowRoot?.querySelector<HTMLDivElement>('.expansion-div');
65    this.expansionUpIcon = this.shadowRoot?.querySelector<LitIcon>('.expansion-up-icon');
66    this.expansionDownIcon = this.shadowRoot?.querySelector<LitIcon>('.expansion-down-icon');
67    let summaryTreeLevel: string[] = ['Level', '/Domain', '/EventName'];
68    this.shadowRoot?.querySelectorAll<HTMLLabelElement>('.head-label').forEach((summaryTreeHead) => {
69      summaryTreeHead.addEventListener('click', () => {
70        this.selectTreeDepth = summaryTreeLevel.indexOf(summaryTreeHead.textContent!);
71        this.expandedNodeList.clear();
72        this.refreshSelectDepth(this.eventTreeNodes);
73        this.refreshRowNodeTable(true);
74      });
75    });
76    this.eventSummaryTable?.addEventListener('scroll', () => {
77      let treeTableEl = this.shadowRoot?.querySelector<HTMLDivElement>('.event-tree-table');
78      if (treeTableEl) {
79        treeTableEl.scrollTop = this.eventSummaryTable?.scrollTop || 0;
80      }
81    });
82  }
83
84  initHtml(): string {
85    return TabPaneHiSysEventSummaryHtml;
86  }
87
88  connectedCallback(): void {
89    super.connectedCallback();
90    new ResizeObserver(() => {
91      this.parentElement!.style.overflow = 'hidden';
92      this.refreshRowNodeTable();
93    }).observe(this.parentElement!);
94    this.expansionDiv?.addEventListener('click', this.expansionClickEvent);
95  }
96
97  expansionClickEvent = (): void => {
98    this.expandedNodeList.clear();
99    if (this.expansionUpIcon?.name === 'down') {
100      this.selectTreeDepth = 0;
101      this.expansionUpIcon!.name = 'up';
102      this.expansionDownIcon!.name = 'down';
103    } else {
104      this.selectTreeDepth = 2;
105      this.expansionUpIcon!.name = 'down';
106      this.expansionDownIcon!.name = 'up';
107    }
108    this.refreshSelectDepth(this.eventTreeNodes);
109    this.refreshRowNodeTable(true);
110  };
111
112  disconnectedCallback(): void {
113    super.disconnectedCallback();
114    this.expansionDiv?.removeEventListener('click', this.expansionClickEvent);
115  }
116
117  private refreshSelectDepth(eventTreeNodes: HiSysEventTreeNode[]): void {
118    eventTreeNodes.forEach((item) => {
119      if (item.depth < this.selectTreeDepth) {
120        this.expandedNodeList.add(item.id);
121        if (item.children.length > 0) {
122          this.refreshSelectDepth(item.children);
123        }
124      }
125    });
126  }
127
128  private createRowNodeTableEL(
129    rowNodeList: HiSysEventTreeNode[],
130    tableTreeEl: HTMLDivElement,
131    tableCountEl: HTMLDivElement,
132    rowColor: string = ''
133  ): void {
134    let unitPadding: number = 20;
135    let leftPadding: number = 5;
136    rowNodeList.forEach((rowNode) => {
137      let tableRowEl: HTMLElement = document.createElement('tr');
138      tableRowEl.className = 'tree-row-tr';
139      tableRowEl.title = rowNode.summaryName!;
140      let tdEl: HTMLElement = document.createElement('td');
141      tdEl.style.paddingLeft = `${rowNode.depth * unitPadding + leftPadding}px`;
142      tableRowEl.appendChild(tdEl);
143      this.addToggleIconEl(rowNode, tableRowEl);
144      let rowNodeTextEL: HTMLElement = document.createElement('td');
145      rowNodeTextEL.textContent = rowNode.summaryName!;
146      rowNodeTextEL.className = 'row-name-td';
147      tableRowEl.appendChild(rowNodeTextEL);
148      tableTreeEl.appendChild(tableRowEl);
149      let tableCountRowEl: HTMLElement = document.createElement('tr');
150      let countEle: HTMLElement = document.createElement('td');
151      countEle.textContent = rowNode.count.toString();
152      countEle.className = 'count-column-td';
153      if (rowNode.depth === 0) {
154        rowNodeTextEL.style.color = ColorUtils.getHisysEventColor(rowNode.summaryName!);
155        countEle.style.color = ColorUtils.getHisysEventColor(rowNode.summaryName!);
156      } else {
157        rowNodeTextEL.style.color = rowColor;
158        countEle.style.color = rowColor;
159      }
160      tableCountRowEl.appendChild(countEle);
161      tableCountEl.appendChild(tableCountRowEl);
162      if (rowNode.children && this.expandedNodeList.has(rowNode.id)) {
163        this.createRowNodeTableEL(rowNode.children, tableTreeEl, tableCountEl, countEle.style.color);
164      }
165    });
166  }
167
168  private addToggleIconEl(rowNode: HiSysEventTreeNode, tableRowEl: HTMLElement): void {
169    let toggleIconEl: HTMLElement = document.createElement('td');
170    let expandIcon = document.createElement('lit-icon');
171    expandIcon.classList.add('tree-icon');
172    if (rowNode.children && rowNode.children.length > 0) {
173      toggleIconEl.appendChild(expandIcon);
174      // @ts-ignore
175      expandIcon.name = this.expandedNodeList.has(rowNode.id) ? 'minus-square' : 'plus-square';
176      toggleIconEl.classList.add('expand-icon');
177      toggleIconEl.addEventListener('click', () => {
178        let scrollTop = this.eventSummaryTable?.scrollTop ?? 0;
179        this.changeNode(rowNode.id);
180        this.eventSummaryTable!.scrollTop = scrollTop;
181      });
182    }
183    tableRowEl.appendChild(toggleIconEl);
184  }
185
186  private refreshRowNodeTable(useCacheRefresh: boolean = false): void {
187    this.eventSummaryTable!.innerHTML = '';
188    if (this.eventSummaryTable && this.parentElement) {
189      this.eventSummaryTable.style.height = `${this.parentElement.clientHeight - NUM_30}px`;
190    }
191    if (!useCacheRefresh) {
192      this.eventTreeNodes = this.buildTreeTblNodes(this.summarySource);
193      if (this.eventTreeNodes.length > 0) {
194        this.summaryTable!.recycleDataSource = this.eventTreeNodes;
195      } else {
196        this.summaryTable!.recycleDataSource = [];
197      }
198    }
199    let tableFragmentEl: DocumentFragment = document.createDocumentFragment();
200    let tableTreeEl: HTMLDivElement = document.createElement('div');
201    tableTreeEl.className = 'event-tree-table';
202    let tableCountEl: HTMLDivElement = document.createElement('div');
203    if (this.parentElement) {
204      tableTreeEl.style.height = `${this.parentElement!.clientHeight - NUM_40}px`;
205    }
206    this.createRowNodeTableEL(this.eventTreeNodes, tableTreeEl, tableCountEl, '');
207    const emptyTr = document.createElement('tr');
208    emptyTr.className = 'tree-row-tr';
209    tableTreeEl?.appendChild(emptyTr);
210    const emptyCountTr = document.createElement('tr');
211    emptyCountTr.className = 'tree-row-tr';
212    tableCountEl?.appendChild(emptyCountTr);
213    tableFragmentEl.appendChild(tableTreeEl);
214    tableFragmentEl.appendChild(tableCountEl);
215    this.eventSummaryTable!.appendChild(tableFragmentEl);
216  }
217
218  private changeNode(currentNode: number): void {
219    if (this.expandedNodeList.has(currentNode)) {
220      this.expandedNodeList.delete(currentNode);
221    } else {
222      this.expandedNodeList.add(currentNode);
223    }
224    this.refreshRowNodeTable();
225  }
226
227  private buildTreeTblNodes(eventTreeNodes: HiSysEventStruct[]): HiSysEventTreeNode[] {
228    let id = 0;
229    let root: HiSysEventTreeNode = { id: id, depth: 0, children: [], summaryName: '', count: 0 };
230    eventTreeNodes.forEach((item) => {
231      id++;
232      let levelNode = root.children.find((node) => node.summaryName === item.level);
233      if (levelNode) {
234        levelNode.count++;
235      } else {
236        id++;
237        levelNode = { id: id, depth: 0, children: [], summaryName: item.level, count: 1 };
238        root.children.push(levelNode);
239      }
240      let domainNode = levelNode.children.find((node) => node.summaryName === item.domain);
241      if (domainNode) {
242        domainNode.count++;
243      } else {
244        id++;
245        domainNode = { id: id, depth: 1, children: [], summaryName: item.domain, count: 1 };
246        levelNode.children.push(domainNode);
247      }
248      let eventNameNode = domainNode.children.find((node) => node.summaryName === item.eventName);
249      if (eventNameNode) {
250        eventNameNode.count++;
251      } else {
252        id++;
253        eventNameNode = { id: id, depth: 2, children: [], summaryName: item.eventName, count: 1 };
254        domainNode.children.push(eventNameNode);
255      }
256      root.count++;
257    });
258    return root.children.sort((leftData, rightData) => {
259      return leftData.summaryName!.length - rightData.summaryName!.length;
260    });
261  }
262}
263
264export interface HiSysEventTreeNode {
265  id: number;
266  depth: number;
267  children: HiSysEventTreeNode[];
268  summaryName: string | undefined;
269  count: number;
270}
271