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.js'; 17import { LitTable } from '../../../../../base-ui/table/lit-table.js'; 18import { HeapDataInterface } from '../../../../../js-heap/HeapDataInterface.js'; 19import { ConstructorComparison, ConstructorItem, ConstructorType } from '../../../../../js-heap/model/UiStruct.js'; 20import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column.js'; 21import '../../../../../base-ui/table/lit-table-column.js'; 22import { TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter.js'; 23import '../TabPaneJsMemoryFilter.js'; 24import { HeapSnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; 25import { LitSelectOption } from '../../../../../base-ui/select/LitSelectOption.js'; 26import { LitSelect } from '../../../../../base-ui/select/LitSelect.js'; 27 28@element('tabpane-comparison') 29export class TabPaneComparison extends BaseElement { 30 private comparisonTableEl: LitTable | undefined | null; 31 private retainerTableEl: LitTable | undefined | null; 32 private comparisonsData: Array<ConstructorComparison> = []; 33 private retainsData: Array<ConstructorItem> = []; 34 private baseFileId: number | undefined | null; 35 private targetFileId: number | undefined | null; 36 private filterEl: TabPaneJsMemoryFilter | undefined | null; 37 private selectEl: LitSelect | undefined | null; 38 private search: HTMLInputElement | undefined | null; 39 private comparisonData: Array<ConstructorItem> = []; 40 private comparisonFilter: Array<ConstructorComparison> = []; 41 private leftArray: Array<ConstructorComparison> = []; 42 private rightArray: Array<ConstructorItem> = []; 43 private rightTheadTable: HTMLDivElement | undefined | null; 44 private leftTheadTable: HTMLDivElement | undefined | null; 45 private comparisonTable: HTMLDivElement | undefined | null; 46 private fileSize: number = 0; 47 48 initElements(): void { 49 this.comparisonTableEl = this.shadowRoot!.querySelector<LitTable>('#tb-comparison') as LitTable; 50 this.retainerTableEl = this.shadowRoot!.querySelector<LitTable>('#tb-retainer') as LitTable; 51 this.filterEl = this.shadowRoot!.querySelector<TabPaneJsMemoryFilter>('#filter'); 52 this.selectEl = this.filterEl?.shadowRoot?.querySelector<LitSelect>('lit-select'); 53 this.search = this.filterEl?.shadowRoot?.querySelector('#js-memory-filter-input') as HTMLInputElement; 54 this.rightTheadTable = this.retainerTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; 55 this.leftTheadTable = this.comparisonTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; 56 this.comparisonTable = this.comparisonTableEl.shadowRoot?.querySelector('.table') as HTMLDivElement; 57 this.comparisonTableEl!.addEventListener('icon-click', (e) => { 58 // @ts-ignore 59 let clickRow = e.detail.data; 60 if (clickRow.status) { 61 clickRow.targetFileId = this.targetFileId; 62 let next = HeapDataInterface.getInstance().getNextForComparison(clickRow); 63 clickRow.children = next; 64 if (clickRow.children.length > 0) { 65 for (let item of clickRow.children) { 66 let nodeName = item.nodeName + ` @${item.id}`; 67 item.nodeId = ` @${item.id}`; 68 if (item.isString()) { 69 item.objectName = '"' + item.nodeName + '"' + ` @${item.id}`; 70 } else { 71 item.objectName = nodeName; 72 } 73 item.deltaCount = '-'; 74 item.deltaSize = '-'; 75 if (item.edgeName != '') { 76 item.objectName = item.edgeName + '\xa0' + '::' + '\xa0' + nodeName; 77 } else { 78 if (item.fileId == this.baseFileId) { 79 item.addedCount = '•'; 80 item.addedSize = item.shallowSize; 81 item.removedCount = '-'; 82 item.removedSize = '-'; 83 } else if (item.fileId) { 84 item.removedCount = '•'; 85 item.removedSize = item.shallowSize; 86 item.addedCount = '-'; 87 item.addedSize = '-'; 88 } 89 } 90 if (item.type == ConstructorType.FiledType) { 91 item.removedCount = '-'; 92 item.removedSize = '-'; 93 item.addedCount = '-'; 94 item.addedSize = '-'; 95 } 96 } 97 } else { 98 this.comparisonTableEl!.snapshotDataSource = []; 99 } 100 } else { 101 clickRow.status = true; 102 } 103 if (this.search!.value != '') { 104 if (this.leftTheadTable!.hasAttribute('sort')) { 105 this.comparisonTableEl!.snapshotDataSource = this.leftArray; 106 } else { 107 this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; 108 } 109 } else { 110 if (this.leftTheadTable!.hasAttribute('sort')) { 111 this.comparisonTableEl!.snapshotDataSource = this.leftArray; 112 } else { 113 this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; 114 } 115 } 116 new ResizeObserver(() => { 117 this.comparisonTableEl!.style.height = '100%'; 118 this.comparisonTableEl!.reMeauseHeight(); 119 }).observe(this.parentElement!); 120 }); 121 this.retainerTableEl!.addEventListener('icon-click', (e) => { 122 // @ts-ignore 123 let retainerNext = e.detail.data as ConstructorItem; 124 if (retainerNext) { 125 if (this.retainsData.length > 0) { 126 if (retainerNext.status) { 127 retainerNext.getChildren(); 128 let i = 0; 129 let that = this; 130 let retainsTable = () => { 131 const getList = (comList: Array<ConstructorItem>) => { 132 comList.forEach((row) => { 133 let shallow = Math.round((row.shallowSize / this.fileSize) * 100) + '%'; 134 let retained = Math.round((row.retainedSize / this.fileSize) * 100) + '%'; 135 row.shallowPercent = shallow; 136 row.retainedPercent = retained; 137 let nodeId = row.nodeName + ` @${row.id}`; 138 row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; 139 if (row.distance >= 100000000 || row.distance == -5) { 140 // @ts-ignore 141 row.distance = '-'; 142 } 143 i++; 144 // @ts-ignore 145 if (i < that.retainsData[0].distance - 1 && comList[0].distance != '-') { 146 comList[0].getChildren(); 147 comList[0].expanded = false; 148 if (row.hasNext) { 149 getList(row.children); 150 } 151 } else { 152 return; 153 } 154 }); 155 }; 156 getList(retainerNext.children); 157 }; 158 retainsTable(); 159 } else { 160 retainerNext.status = true; 161 } 162 if (this.rightTheadTable!.hasAttribute('sort')) { 163 this.retainerTableEl!.snapshotDataSource = this.rightArray; 164 } else { 165 this.retainerTableEl!.snapshotDataSource = this.retainsData; 166 } 167 } else { 168 this.retainerTableEl!.snapshotDataSource = []; 169 } 170 new ResizeObserver(() => { 171 this.retainerTableEl!.style.height = 'calc(100% - 21px)'; 172 this.retainerTableEl!.reMeauseHeight(); 173 }).observe(this.parentElement!); 174 } 175 }); 176 this.comparisonTableEl!.addEventListener('column-click', (e) => { 177 // @ts-ignore 178 this.sortComprisonByColumn(e.detail.key, e.detail.sort); 179 this.comparisonTableEl!.reMeauseHeight(); 180 }); 181 this.retainerTableEl!.addEventListener('column-click', (e) => { 182 // @ts-ignore 183 this.sortRetainerByColumn(e.detail.key, e.detail.sort); 184 this.retainerTableEl!.reMeauseHeight(); 185 }); 186 this.comparisonTableEl!.addEventListener('row-click', (e) => { 187 this.rightTheadTable!.removeAttribute('sort'); 188 // @ts-ignore 189 let item = e.detail.data as ConstructorItem; 190 (item as any).isSelected = true; 191 this.retainsData = HeapDataInterface.getInstance().getRetains(item); 192 if (this.retainsData && this.retainsData.length > 0) { 193 this.retainsData.forEach((comparisonRetainEl) => { 194 let shallow = Math.round((comparisonRetainEl.shallowSize / this.fileSize) * 100) + '%'; 195 let retained = Math.round((comparisonRetainEl.retainedSize / this.fileSize) * 100) + '%'; 196 comparisonRetainEl.shallowPercent = shallow; 197 comparisonRetainEl.retainedPercent = retained; 198 if (comparisonRetainEl.distance >= 100000000 || comparisonRetainEl.distance === -5) { 199 // @ts-ignore 200 comparisonRetainEl.distance = '-'; 201 } 202 let nodeId = comparisonRetainEl.nodeName + ` @${comparisonRetainEl.id}`; 203 comparisonRetainEl.objectName = comparisonRetainEl.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; 204 }); 205 let i = 0; 206 let that = this; 207 if (this.retainsData[0].distance > 1) { 208 this.retainsData[0].getChildren(); 209 this.retainsData[0].expanded = false; 210 } 211 let retainsTable = () => { 212 const getList = (list: Array<ConstructorItem>) => { 213 list.forEach((structRow) => { 214 let shallow = Math.round((structRow.shallowSize / this.fileSize) * 100) + '%'; 215 let retained = Math.round((structRow.retainedSize / this.fileSize) * 100) + '%'; 216 structRow.shallowPercent = shallow; 217 structRow.retainedPercent = retained; 218 let nodeId = structRow.nodeName + ` @${structRow.id}`; 219 structRow.objectName = structRow.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; 220 if (structRow.distance >= 100000000 || structRow.distance === -5) { 221 // @ts-ignore 222 structRow.distance = '-'; 223 } 224 i++; 225 // @ts-ignore 226 if (i < that.retainsData[0].distance - 1 && list[0].distance != '-') { 227 list[0].getChildren(); 228 list[0].expanded = false; 229 if (structRow.hasNext) { 230 getList(structRow.children); 231 } 232 } else { 233 return; 234 } 235 }); 236 }; 237 getList(that.retainsData[0].children); 238 }; 239 retainsTable(); 240 this.retainerTableEl!.snapshotDataSource = this.retainsData; 241 } else { 242 this.retainerTableEl!.snapshotDataSource = []; 243 } 244 new ResizeObserver(() => { 245 this.retainerTableEl!.style.height = 'calc(100% - 21px)'; 246 this.retainerTableEl!.reMeauseHeight(); 247 }).observe(this.parentElement!); 248 // @ts-ignore 249 if ((e.detail as any).callBack) { 250 // @ts-ignore 251 (e.detail as any).callBack(true); 252 } 253 }); 254 this.retainerTableEl!.addEventListener('row-click', (evt: any) => { 255 let data = evt.detail.data as ConstructorItem; 256 (data as any).isSelected = true; 257 if ((evt.detail as any).callBack) { 258 (evt.detail as any).callBack(true); 259 } 260 }); 261 this.classFilter(); 262 } 263 264 initComparison(data: HeapSnapshotStruct, dataList: Array<HeapSnapshotStruct>) { 265 this.clear(); 266 this.retainerTableEl!.snapshotDataSource = []; 267 let fileArr: HeapSnapshotStruct[] = []; 268 let that = this; 269 for (let file of dataList) { 270 if (file.id !== data.id) { 271 fileArr.push(file); 272 } 273 } 274 fileArr = fileArr.sort(); 275 this.fileSize = data.size; 276 this.initSelect(data.id, fileArr); 277 this.baseFileId = data.id; 278 this.targetFileId = fileArr[0].id; 279 that.updateComparisonData(data.id, fileArr[0].id); 280 new ResizeObserver(() => { 281 this.comparisonTableEl!.style.height = '100%'; 282 this.comparisonTableEl!.reMeauseHeight(); 283 }).observe(this.parentElement!); 284 } 285 286 updateComparisonData(baseFileId: number, targetFileId: number) { 287 this.comparisonsData = HeapDataInterface.getInstance().getClassListForComparison(baseFileId, targetFileId); 288 this.comparisonsData.forEach((dataList) => { 289 dataList.objectName = dataList.nodeName; 290 }); 291 if (this.comparisonsData.length > 0) { 292 this.comparisonData = this.comparisonsData; 293 this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; 294 } else { 295 this.comparisonTableEl!.snapshotDataSource = []; 296 } 297 this.comparisonTableEl!.reMeauseHeight(); 298 } 299 300 initSelect(fileId: number, comFileArr: Array<HeapSnapshotStruct>) { 301 let that = this; 302 let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement; 303 this.selectEl!.innerHTML = ''; 304 let option = new LitSelectOption(); 305 option.innerHTML = 'File Name'; 306 option.setAttribute('disabled', 'disabled'); 307 this.selectEl?.appendChild(option); 308 if (comFileArr[0].name) { 309 option.setAttribute('value', comFileArr[0].name); 310 } 311 this.selectEl!.defaultValue = comFileArr[0].name || ''; 312 this.selectEl!.placeholder = comFileArr[0].name || ''; 313 this.selectEl!.dataSource = comFileArr; 314 this.selectEl!.querySelectorAll('lit-select-option').forEach((a) => { 315 a.addEventListener('onSelected', (e) => { 316 this.comparisonTable!.scrollTop = 0; 317 this.retainerTableEl!.snapshotDataSource = []; 318 for (let f of comFileArr) { 319 if (input.value == f.name) { 320 that.updateComparisonData(fileId, f.id); 321 } 322 } 323 e.stopPropagation(); 324 }); 325 }); 326 } 327 328 sortComprisonByColumn(column: string, sort: number) { 329 switch (sort) { 330 case 0: 331 if (this.search!.value === '') { 332 this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; 333 } else { 334 this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; 335 } 336 break; 337 default: 338 if (this.search!.value === '') { 339 this.leftArray = [...this.comparisonsData]; 340 } else { 341 this.leftArray = [...this.comparisonFilter]; 342 } 343 switch (column) { 344 case 'addedCount': 345 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 346 return sort === 1 ? a.addedCount - b.addedCount : b.addedCount - a.addedCount; 347 }); 348 break; 349 case 'removedCount': 350 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 351 return sort === 1 ? a.removedCount - b.removedCount : b.removedCount - a.removedCount; 352 }); 353 break; 354 case 'deltaCount': 355 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 356 return sort === 1 ? a.deltaCount - b.deltaCount : b.deltaCount - a.deltaCount; 357 }); 358 break; 359 case 'objectName': 360 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 361 return sort === 1 362 ? (a.objectName + '').localeCompare(b.objectName + '') 363 : (b.objectName + '').localeCompare(a.objectName + ''); 364 }); 365 break; 366 case 'addedSize': 367 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 368 return sort === 1 ? a.addedSize - b.addedSize : b.addedSize - a.addedSize; 369 }); 370 break; 371 case 'removedSize': 372 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 373 return sort === 1 ? a.removedSize - b.removedSize : b.removedSize - a.removedSize; 374 }); 375 break; 376 case 'deltaSize': 377 this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { 378 return sort === 1 ? a.deltaSize - b.deltaSize : b.deltaSize - a.deltaSize; 379 }); 380 break; 381 } 382 break; 383 } 384 } 385 386 sortRetainerByColumn(column: string, sort: number) { 387 switch (sort) { 388 case 0: 389 this.retainerTableEl!.snapshotDataSource = this.retainsData; 390 break; 391 default: 392 this.rightArray = [...this.retainsData]; 393 switch (column) { 394 case 'distance': 395 this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => { 396 return sort === 1 ? a.distance - b.distance : b.distance - a.distance; 397 }); 398 this.rightArray.forEach((list) => { 399 let retainsTable = function () { 400 const getList = function (currentList: Array<ConstructorItem>) { 401 currentList.sort((a, b) => { 402 return sort === 1 ? a.distance - b.distance : b.distance - a.distance; 403 }); 404 currentList.forEach(function (currentRow) { 405 if (currentRow.children.length > 0) { 406 getList(currentRow.children); 407 } 408 }); 409 }; 410 getList(list.children); 411 }; 412 retainsTable(); 413 }); 414 this.retainerTableEl!.snapshotDataSource = this.rightArray; 415 break; 416 case 'shallowSize': 417 this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => { 418 return sort === 1 419 ? rightArrA.shallowSize - rightArrB.shallowSize 420 : rightArrB.shallowSize - rightArrA.shallowSize; 421 }); 422 this.rightArray.forEach((list) => { 423 let retainsTable = function () { 424 const getList = function (listArr: Array<ConstructorItem>) { 425 listArr.sort((listArrA, listArrB) => { 426 return sort === 1 427 ? listArrA.shallowSize - listArrB.shallowSize 428 : listArrB.shallowSize - listArrA.shallowSize; 429 }); 430 listArr.forEach(function (rowEl) { 431 if (rowEl.children.length > 0) { 432 getList(rowEl.children); 433 } 434 }); 435 }; 436 getList(list.children); 437 }; 438 retainsTable(); 439 }); 440 this.retainerTableEl!.snapshotDataSource = this.rightArray; 441 break; 442 case 'retainedSize': 443 this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => { 444 return sort === 1 445 ? rightArrA.retainedSize - rightArrB.retainedSize 446 : rightArrB.retainedSize - rightArrA.retainedSize; 447 }); 448 this.rightArray.forEach((list) => { 449 let retainsTable = function () { 450 const getList = function (listArr: Array<ConstructorItem>) { 451 listArr.sort((listArrA, listArrB) => { 452 return sort === 1 453 ? listArrA.retainedSize - listArrB.retainedSize 454 : listArrB.retainedSize - listArrA.retainedSize; 455 }); 456 listArr.forEach(function (row) { 457 if (row.children.length > 0) { 458 getList(row.children); 459 } 460 }); 461 }; 462 getList(list.children); 463 }; 464 retainsTable(); 465 }); 466 this.retainerTableEl!.snapshotDataSource = this.rightArray; 467 break; 468 case 'objectName': 469 this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => { 470 return sort === 1 471 ? (rightArrA.objectName + '').localeCompare(rightArrB.objectName + '') 472 : (rightArrB.objectName + '').localeCompare(rightArrA.objectName + ''); 473 }); 474 this.rightArray.forEach((list) => { 475 let retainsTable = function () { 476 const getList = function (listArr: Array<ConstructorItem>) { 477 listArr.sort((listArrA, listArrB) => { 478 return sort === 1 479 ? (listArrA.objectName + '').localeCompare(listArrB.objectName + '') 480 : (listArrB.objectName + '').localeCompare(listArrA.objectName + ''); 481 }); 482 listArr.forEach(function (currentRow) { 483 if (currentRow.children.length > 0) { 484 getList(currentRow.children); 485 } 486 }); 487 }; 488 getList(list.children); 489 }; 490 retainsTable(); 491 }); 492 this.retainerTableEl!.snapshotDataSource = this.rightArray; 493 break; 494 } 495 break; 496 } 497 } 498 499 classFilter() { 500 this.search!.addEventListener('keyup', () => { 501 this.comparisonFilter = []; 502 this.comparisonData.forEach((a: any, key: number) => { 503 if (a.objectName.toLowerCase().includes(this.search!.value.toLowerCase())) { 504 this.comparisonFilter.push(a); 505 } else { 506 } 507 }); 508 this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; 509 let summaryTable = this.comparisonTableEl!.shadowRoot?.querySelector('.table') as HTMLDivElement; 510 summaryTable.scrollTop = 0; 511 this.comparisonTableEl!.reMeauseHeight(); 512 }); 513 } 514 515 clear() { 516 this.search!.value = ''; 517 this.rightTheadTable!.removeAttribute('sort'); 518 this.leftTheadTable!.removeAttribute('sort'); 519 this.comparisonTable!.scrollTop = 0; 520 } 521 522 connectedCallback() { 523 super.connectedCallback(); 524 let filterHeight = 0; 525 new ResizeObserver((entries) => { 526 let comparisonPanelFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; 527 if (comparisonPanelFilter.clientHeight > 0) filterHeight = comparisonPanelFilter.clientHeight; 528 if (this.parentElement!.clientHeight > filterHeight) { 529 comparisonPanelFilter.style.display = 'flex'; 530 } else { 531 comparisonPanelFilter.style.display = 'none'; 532 } 533 }).observe(this.parentElement!); 534 } 535 536 initHtml(): string { 537 return ` 538 <style> 539 :host{ 540 display: flex; 541 flex-direction: column; 542 padding: 10px 10px 0 10px; 543 height: calc(100% - 10px - 31px); 544 } 545 .show{ 546 display: flex; 547 flex: 1; 548 } 549 .progress{ 550 bottom: 33px; 551 position: absolute; 552 height: 1px; 553 left: 0; 554 right: 0; 555 } 556 selector{ 557 display: none; 558 } 559 tab-pane-filter { 560 border: solid rgb(216,216,216) 1px; 561 float: left; 562 position: fixed; 563 bottom: 0; 564 width: 100%; 565 } 566 .loading{ 567 bottom: 0; 568 position: absolute; 569 left: 0; 570 right: 0; 571 width:100%; 572 background:transparent; 573 z-index: 999999; 574 } 575 </style> 576 <div style="display: flex;flex-direction: row;height: 100%;"> 577 <selector id='show_table' class="show"> 578 <lit-slicer style="width:100%"> 579 <div style="width: 65%"> 580 <lit-table id="tb-comparison" style="height: auto" tree> 581 <lit-table-column width="30%" title="#Constructor" data-index="" key="objectName" align="flex-start" order> 582 </lit-table-column> 583 <lit-table-column width="1fr" title="#New" data-index="addedCount" key="addedCount" align="flex-start" order> 584 </lit-table-column> 585 <lit-table-column width="1fr" title="#Deleted" data-index="removedCount" key="removedCount" align="flex-start" order> 586 </lit-table-column> 587 <lit-table-column width="1fr" title="#Delta" data-index="deltaCount" key="deltaCount" align="flex-start" order> 588 </lit-table-column> 589 <lit-table-column width="1fr" title="Alloc.Size" data-index="addedSize" key="addedSize" align="flex-start" order> 590 </lit-table-column> 591 <lit-table-column width="1fr" title="Freed Size" data-index="removedSize" key="removedSize" align="flex-start" order> 592 </lit-table-column> 593 <lit-table-column width="1fr" title="Size Delta" data-index="deltaSize" key="deltaSize" align="flex-start" order> 594 </lit-table-column> 595 </lit-table> 596 </div> 597 <lit-slicer-track ></lit-slicer-track> 598 <div style="flex: 1;display: flex; flex-direction: row;"> 599 <div style="flex: 1;display: flex; flex-direction: column;"> 600 <span slot="head" >Retainers</span> 601 <lit-table id="tb-retainer" style="height: calc(100% - 21px);" tree> 602 <lit-table-column width="30%" title="Object" data-index="" key="objectName" align="flex-start" order> 603 </lit-table-column> 604 <lit-table-column width="1fr" title="distance" data-index="distance" key="distance" align="flex-start" order> 605 </lit-table-column> 606 <lit-table-column width="1fr" title="ShallowSize" data-index="shallowSize" key="shallowSize" align="flex-start" order> 607 </lit-table-column> 608 <lit-table-column width="1fr" title="" data-index="shallowPercent" key="shallowPercent" align="flex-start"> 609 </lit-table-column> 610 <lit-table-column width="1fr" title="RetainedSize" data-index="retainedSize" key="retainedSize" align="flex-start" order> 611 </lit-table-column> 612 <lit-table-column width="1fr" title="" data-index="retainedPercent" key="retainedPercent" align="flex-start"> 613 </lit-table-column> 614 </div> 615 </div> 616 </lit-table> 617 </lit-slicer> 618 </selector> 619 <lit-progress-bar class="progress"></lit-progress-bar> 620 <tab-pane-js-memory-filter id="filter" input inputLeftText first ></tab-pane-js-memory-filter> 621 <div class="loading"></div> 622 </div> 623 `; 624 } 625} 626