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