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