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