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