Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: table tabs render improvements #398

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions log-viewer/modules/analysis-view/AnalysisView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ import { RootNode, TimedNode } from '../parsers/TreeParser';
import { hostService } from '../services/VSCodeService';

let analysisTable: Tabulator;
let tableContainer: HTMLDivElement;
let tableContainer: HTMLDivElement | null;
@customElement('analysis-view')
export class AnalysisView extends LitElement {
@property()
timelineRoot: RootNode | null = null;

get _tableWrapper(): HTMLDivElement | null {
return (tableContainer = this.renderRoot?.querySelector('#analysis-table') ?? null);
}

constructor() {
super();
}

updated(changedProperties: PropertyValues): void {
const timlineRoot = changedProperties.has('timelineRoot');
if (this.timelineRoot && timlineRoot) {
tableContainer = this.shadowRoot?.getElementById('analysis-table') as HTMLDivElement;
if (tableContainer) {
initAnalysisRender(tableContainer, this.timelineRoot);
}
if (this.timelineRoot && changedProperties.has('timelineRoot')) {
this._appendTableWhenVisible();
}
}

Expand Down Expand Up @@ -72,22 +72,27 @@ export class AnalysisView extends LitElement {
const checkBox = event.target as HTMLInputElement;
analysisTable.setGroupBy(checkBox.checked ? 'type' : '');
}
}

export function initAnalysisRender(analysisRoot: HTMLElement, rootMethod: RootNode) {
if (analysisRoot) {
const analysisObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
renderAnalysis(rootMethod);
observer.disconnect();
}
});
analysisObserver.observe(analysisRoot);
_appendTableWhenVisible() {
const rootMethod = this.timelineRoot;
const tableWrapper = this._tableWrapper;
if (tableWrapper && rootMethod) {
const analysisObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
renderAnalysis(rootMethod);
observer.disconnect();
}
});
analysisObserver.observe(tableWrapper);
}
}
}

async function renderAnalysis(rootMethod: RootNode) {
if (!tableContainer) {
return;
}
const methodMap: Map<string, Metric> = new Map();

addNodeToMap(methodMap, rootMethod);
Expand Down
55 changes: 27 additions & 28 deletions log-viewer/modules/calltree-view/CalltreeView.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2022 Certinia Inc. All rights reserved.
*/
// todo: add breakcrumbs back? - I will do this but in a later PR + better
// todo: add breadcrumbs back? - I will do this but in a later PR + better
//
//todo: ** future **
//todo: show total and self as percentage of total? + do the same on the analysis view?
Expand All @@ -24,29 +24,24 @@ import { hostService } from '../services/VSCodeService';
import treeViewStyles from './TreeView.scss';

let calltreeTable: Tabulator;
let tableContainer: HTMLDivElement;
let tableContainer: HTMLDivElement | null;

@customElement('call-tree-view')
export class CalltreeView extends LitElement {
@property()
timelineRoot: RootNode | null = null;

get _callTreeTableWrapper(): HTMLDivElement | null {
return (tableContainer = this.renderRoot?.querySelector('#call-tree-table') ?? null);
}

constructor() {
super();
}

updated(changedProperties: PropertyValues): void {
const timlineRoot = changedProperties.has('timelineRoot');
if (this.timelineRoot && timlineRoot) {
const calltreeContainer = this.shadowRoot?.getElementById(
'call-tree-table-container'
) as HTMLDivElement;

tableContainer = this.shadowRoot?.getElementById('call-tree-table') as HTMLDivElement;

if (calltreeContainer) {
initCalltree(calltreeContainer, tableContainer, this.timelineRoot);
}
if (this.timelineRoot && changedProperties.has('timelineRoot')) {
this._appendTableWhenVisible();
}
}

Expand Down Expand Up @@ -128,22 +123,20 @@ export class CalltreeView extends LitElement {
collapseAll(calltreeTable.getRows());
calltreeTable.restoreRedraw();
}
}

export function initCalltree(
callTreeView: HTMLDivElement,
callTreeTable: HTMLDivElement,
rootMethod: RootNode
) {
if (callTreeView) {
const analysisObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
renderCallTree(callTreeTable, rootMethod);
observer.disconnect();
}
});
analysisObserver.observe(callTreeView);
_appendTableWhenVisible() {
const callTreeWrapper = this._callTreeTableWrapper;
const rootMethod = this.timelineRoot;
if (callTreeWrapper && rootMethod) {
const analysisObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
renderCallTree(callTreeWrapper, rootMethod);
observer.disconnect();
}
});
analysisObserver.observe(callTreeWrapper);
}
}
}

Expand All @@ -152,6 +145,8 @@ export async function renderCallTree(
rootMethod: RootNode
): Promise<void> {
if (calltreeTable) {
// Ensure the table is fully visible before attempting to do things e.g go to rows.
// Otherwise there are visible rendering issues.
await new Promise((resolve, reject) => {
const visibilityObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting && entries[0].intersectionRatio > 0;
Expand Down Expand Up @@ -398,6 +393,10 @@ function toCallTree(nodes: LogLine[]): CalltreeRow[] | undefined {
}

export async function goToRow(timestamp: number) {
if (!tableContainer) {
return;
}

document.dispatchEvent(new CustomEvent('show-tab', { detail: { tabid: 'tree-tab' } }));
await renderCallTree(tableContainer, rootMethod);

Expand Down
53 changes: 53 additions & 0 deletions log-viewer/modules/components/BadgeBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 Certinia Inc. All rights reserved.
*/
import { provideVSCodeDesignSystem, vsCodeTag } from '@vscode/webview-ui-toolkit';
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';

import { globalStyles } from '../global.styles';

provideVSCodeDesignSystem().register(vsCodeTag());

@customElement('badge-base')
export class BadgeBase extends LitElement {
@property()
status: 'success' | 'failure' | 'neutral' = 'neutral';
colorMap = new Map<string, string>([
['success', 'success-tag'],
['failure', 'failure-tag'],
]);

static styles = [
globalStyles,
css`
:host {
}

.tag {
font-family: monospace;
font-size: inherit;
}

.tag::part(control) {
color: var(--vscode-editor-foreground);
background-color: var(--button-icon-hover-background, rgba(90, 93, 94, 0.31));
text-transform: inherit;
border: none;
}
.success-tag::part(control) {
background-color: rgba(128, 255, 128, 0.2);
}

.failure-tag::part(control) {
background-color: var(--notification-error-background);
}
`,
];

render() {
const statusTag = this.colorMap.get(this.status);

return html`<vscode-tag class="tag ${statusTag}"><slot></slot></vscode-tag>`;
}
}
5 changes: 4 additions & 1 deletion log-viewer/modules/database-view/DatabaseSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';

import '../components/BadgeBase';
import { globalStyles } from '../global.styles';
import { Method } from '../parsers/TreeParser';

Expand Down Expand Up @@ -40,7 +41,9 @@ export class DatabaseSection extends LitElement {

return html`
<div class="dbSection">
<span class="dbTitle">${this.title} (Count: ${totalCount}, Rows: ${totalRows})</span>
<span class="dbTitle">${this.title}</span>
<badge-base>Count: ${totalCount}</badge-base>
<badge-base>Rows: ${totalRows}</badge-base>
</div>
`;
}
Expand Down
69 changes: 35 additions & 34 deletions log-viewer/modules/database-view/DatabaseView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@

let soqlTable: Tabulator;
let dmlTable: Tabulator;
let dmlTableContainer: HTMLDivElement;
let soqlTableContainer: HTMLDivElement;

@customElement('database-view')
export class DatabaseView extends LitElement {
@property()
Expand All @@ -42,22 +41,21 @@
@state()
soqlLines: SOQLExecuteBeginLine[] = [];

get _dmlTableWrapper(): HTMLDivElement | null {
return this.renderRoot?.querySelector('#db-dml-table') ?? null;
}

get _soqlTableWrapper(): HTMLDivElement | null {
return this.renderRoot?.querySelector('#db-soql-table') ?? null;
}

constructor() {
super();
}

async updated(changedProperties: PropertyValues): Promise<void> {
const timlineRoot = changedProperties.has('timelineRoot');
if (this.timelineRoot && timlineRoot) {
DatabaseAccess.create(this.timelineRoot);
this.dmlLines = DatabaseAccess.instance()?.getDMLLines() || [];
this.soqlLines = DatabaseAccess.instance()?.getSOQLLines() || [];

dmlTableContainer = this.shadowRoot?.getElementById('db-dml-table') as HTMLDivElement;
soqlTableContainer = this.shadowRoot?.getElementById('db-soql-table') as HTMLDivElement;
if (dmlTableContainer) {
initDBRender(dmlTableContainer, soqlTableContainer, this.dmlLines, this.soqlLines);
}
updated(changedProperties: PropertyValues): void {
if (this.timelineRoot && changedProperties.has('timelineRoot')) {
this._appendTableWhenVisible();
}
}

Expand Down Expand Up @@ -126,7 +124,7 @@
id="db-soql-groupby-checkbox"
type="checkbox"
checked
@change=${this.soqlGroupBy}
@change=${this._soqlGroupBy}
/>
<label for="db-soql-groupby-checkbox">SOQL</label>
</div>
Expand All @@ -144,29 +142,32 @@
dmlTable.setGroupBy(checkBox.checked ? 'dml' : '');
}

soqlGroupBy(event: Event) {
_soqlGroupBy(event: Event) {
const checkBox = event.target as HTMLInputElement;
soqlTable.setGroupBy(checkBox.checked ? 'soql' : '');
}
}

export async function initDBRender(
dmlTable: HTMLElement,
soqlTable: HTMLElement,
dmlLines: DMLBeginLine[],
soqlLines: SOQLExecuteBeginLine[]
) {
if (dmlTable) {
const dbObserver = new IntersectionObserver((entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
observer.disconnect();
Tabulator.registerModule([RowKeyboardNavigation]);
renderDMLTable(dmlTable, dmlLines);
renderSOQLTable(soqlTable, soqlLines);
}
});
dbObserver.observe(dmlTable);
async _appendTableWhenVisible() {
const dmlTableWrapper = this._dmlTableWrapper;
const soqlTableWrapper = this._soqlTableWrapper;
const treeRoot = this.timelineRoot;
if (dmlTableWrapper && soqlTableWrapper && treeRoot) {
const dbObserver = new IntersectionObserver(async (entries, observer) => {
const visible = entries[0].isIntersecting;
if (visible) {
observer.disconnect();

const dbAccess = await DatabaseAccess.create(treeRoot);
this.dmlLines = dbAccess.getDMLLines() || [];
this.soqlLines = dbAccess.getSOQLLines() || [];

Tabulator.registerModule([RowKeyboardNavigation]);
renderDMLTable(dmlTableWrapper, this.dmlLines);
renderSOQLTable(soqlTableWrapper, this.soqlLines);
}
});
dbObserver.observe(dmlTableWrapper);
}
}
}

Expand Down Expand Up @@ -213,7 +214,7 @@
groupClosedShowCalcs: true,
groupStartOpen: false,
groupValues: [dmlText],
groupHeader(value, count, data: any[], _group) {

Check warning on line 217 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
const hasDetail = data.some((d) => {
return d.isDetail;
});
Expand Down Expand Up @@ -395,7 +396,7 @@
groupClosedShowCalcs: true,
groupStartOpen: false,
groupValues: [soqlText],
groupHeader(value, count, data: any[], _group) {

Check warning on line 399 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
const hasDetail = data.some((d) => {
return d.isDetail;
});
Expand Down Expand Up @@ -466,20 +467,20 @@
return title;
},
accessorDownload: function (
_value: any,

Check warning on line 470 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
data: any,

Check warning on line 471 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
_type: 'data' | 'download' | 'clipboard',
_accessorParams: any,

Check warning on line 473 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
_column?: ColumnComponent,
_row?: RowComponent
): any {

Check warning on line 476 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
return data.relativeCost;
},
accessorClipboard: function (
_value: any,

Check warning on line 480 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
data: any,

Check warning on line 481 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
_type: 'data' | 'download' | 'clipboard',
_accessorParams: any,

Check warning on line 483 in log-viewer/modules/database-view/DatabaseView.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
_column?: ColumnComponent,
_row?: RowComponent
): any {
Expand Down
13 changes: 7 additions & 6 deletions log-viewer/modules/navbar/NavBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { provideVSCodeDesignSystem, vsCodeButton, vsCodeTag } from '@vscode/webv
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';

import '../components/BadgeBase';
import '../components/LogTitle';
import { globalStyles } from '../global.styles';
import { notificationStyles } from '../notification.styles';
Expand Down Expand Up @@ -110,21 +111,21 @@ export class NavBar extends LitElement {
const sizeText = this.logSize ? (this.logSize / 1000000).toFixed(2) + ' MB' : '',
elapsedText = this._toDuration(this.logDuration);

const statusClass =
const status =
this.notifications.length > 0
? 'failure-tag'
? 'failure'
: this.logStatus !== 'Processing...'
? 'success-tag'
? 'success'
: '';

return html`
<div class="navbar">
<div class="navbar--left">
<div id="status" class="status__bar">
<log-title logName="${this.logName}" logPath="${this.logPath}"></log-title>
<vscode-tag class="status-tag">${sizeText}</vscode-tag>
<vscode-tag class="status-tag">${elapsedText}</vscode-tag>
<vscode-tag class="status-tag ${statusClass}">${this.logStatus}</vscode-tag>
<badge-base>${sizeText}</badge-base>
<badge-base>${elapsedText}</badge-base>
<badge-base status="${status}">${this.logStatus}</badge-base>
<notification-tag .notifications="${this.notifications}"></notification-tag>
</div>
</div>
Expand Down
Loading
Loading