Skip to content
Open
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
12 changes: 7 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- 🎯 **Call Tree Go To**: Go-to links in call tree now navigate to method definition instead of where method was called from ([#632] [#200])
- 🎯 **Call Tree Go To**: Go-to links in call tree now navigate to method definition instead of where method was called from. ([#632] [#200])
- πŸ” **Search Navigation**: `Shift+Enter` navigates to the previous search result; hold `Enter` to continuously navigate.
- ⚑ **Log Parsing**: Improved performance ([#552])
- ✨ **Duration Formatting**: Human-readable duration formatting in tooltips (30000 ms -> 30s and 0.01 ms -> 10 ¡s) ([#671])
- 🎯 **Number Precision**: Total and Self Time column precision changed to 2 decimal places for improved readability ([#671])
- 🎨 **Navigation Bar**: Redesigned to better match VS Code’s look and feel ([#694])
- ⚑ **Search Performance**: Up to 10x faster search on large logs. ([#627])
- ⚑ **Log Parsing**: Improved performance. ([#552])
- ✨ **Duration Formatting**: Human-readable duration formatting in tooltips (30000 ms -> 30s and 0.01 ms -> 10 ¡s). ([#671])
- 🎯 **Number Precision**: Total and Self Time column precision changed to 2 decimal places for improved readability. ([#671])
- 🎨 **Navigation Bar**: Redesigned to better match VS Code’s look and feel. ([#694])

## [1.18.1] 2025-07-09

Expand Down Expand Up @@ -476,6 +477,7 @@ Skipped due to adopting odd numbering for pre releases and even number for relea

<!-- Unreleased -->

[#627]: https://github.com/certinia/debug-log-analyzer/issues/627
[#685]: https://github.com/certinia/debug-log-analyzer/issues/685
[#98]: https://github.com/certinia/debug-log-analyzer/issues/98
[#204]: https://github.com/certinia/debug-log-analyzer/issues/204
Expand Down
45 changes: 28 additions & 17 deletions log-viewer/src/features/analysis/components/AnalysisView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { progressFormatterMS } from '../../../tabulator/format/ProgressMS.js';
import { GroupCalcs } from '../../../tabulator/groups/GroupCalcs.js';
import { GroupSort } from '../../../tabulator/groups/GroupSort.js';
import * as CommonModules from '../../../tabulator/module/CommonModules.js';
import { Find, formatter } from '../../../tabulator/module/Find.js';
import { Find } from '../../../tabulator/module/Find.js';
import { RowKeyboardNavigation } from '../../../tabulator/module/RowKeyboardNavigation.js';
import { RowNavigation } from '../../../tabulator/module/RowNavigation.js';
import dataGridStyles from '../../../tabulator/style/DataGrid.scss';
Expand Down Expand Up @@ -126,6 +126,13 @@ export class AnalysisView extends LitElement {
document.addEventListener('lv-find-close', this._findEvt);
}

disconnectedCallback(): void {
super.disconnectedCallback();
document.removeEventListener('lv-find', this._findEvt);
document.removeEventListener('lv-find-match', this._findEvt);
document.removeEventListener('lv-find-close', this._findEvt);
}

updated(changedProperties: PropertyValues): void {
if (
this.timelineRoot &&
Expand Down Expand Up @@ -251,19 +258,12 @@ export class AnalysisView extends LitElement {
return;
}
this.blockClearHighlights = true;
this.analysisTable?.blockRedraw();
const currentRow = this.findMap[this.findArgs.count];
const rows = [
currentRow,
this.findMap[this.findArgs.count + 1],
this.findMap[this.findArgs.count - 1],
];
rows.forEach((row) => {
row?.reformat();
//@ts-expect-error This is a custom function added in by Find custom module
await this.analysisTable.setCurrentMatch(this.findArgs.count, currentRow, {
scrollIfVisible: false,
focusRow: false,
});
//@ts-expect-error This is a custom function added in by RowNavigation custom module
this.analysisTable.goToRow(currentRow, { scrollIfVisible: false, focusRow: false });
this.analysisTable?.restoreRedraw();
this.blockClearHighlights = false;
}

Expand Down Expand Up @@ -321,9 +321,6 @@ export class AnalysisView extends LitElement {
groupClosedShowCalcs: true,
groupStartOpen: false,
groupToggleElement: 'header',
rowFormatter: (row: RowComponent) => {
formatter(row, this.findArgs);
},
columnDefaults: {
title: 'default',
resizable: true,
Expand Down Expand Up @@ -426,7 +423,21 @@ export class AnalysisView extends LitElement {
],
});

this.analysisTable.on('renderStarted', () => {
this.analysisTable.on('dataSorted', () => {
if (!this.blockClearHighlights && this.totalMatches > 0) {
this._resetFindWidget();
this._clearSearchHighlights();
}
});

this.analysisTable.on('dataFiltered', () => {
if (!this.blockClearHighlights && this.totalMatches > 0) {
this._resetFindWidget();
this._clearSearchHighlights();
}
});

this.analysisTable.on('dataGrouped', () => {
if (!this.blockClearHighlights && this.totalMatches > 0) {
this._resetFindWidget();
this._clearSearchHighlights();
Expand All @@ -442,7 +453,7 @@ export class AnalysisView extends LitElement {
this.findArgs.text = '';
this.findArgs.count = 0;
//@ts-expect-error This is a custom function added in by Find custom module
this.analysisTable.clearFindHighlights(Object.values(this.findMap));
this.analysisTable.clearFindHighlights();
this.findMap = {};
this.totalMatches = 0;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022 Certinia Inc. All rights reserved.
*/
import type { LogEvent, LogEventType } from 'apex-log-parser';
import type { CellComponent, EmptyCallback } from 'tabulator-tables';

export function createCalltreeNameFormatter(excludedTypes: Set<LogEventType>) {
let childIndent: number;

return function calltreeNameFormatter(
cell: CellComponent,
_formatterParams: object,
_onRendered: EmptyCallback,
): string | HTMLElement {
const data = cell.getData() as { originalData: LogEvent; treeLevel: number };
const { originalData: node, treeLevel } = data;
// @ts-expect-error this.table is added by tabulator when the formatter is called, but isn't in the types for some reason
childIndent ??= this.table.options.dataTreeChildIndent ?? 9;
const levelIndent = treeLevel * childIndent;

const cellElem = cell.getElement();
cellElem.style.paddingLeft = `${levelIndent + 4}px`;
cellElem.style.textIndent = `-${levelIndent}px`;

if (node.hasValidSymbols) {
const link = document.createElement('a');
link.setAttribute('href', '#!');
link.textContent = node.text;
return link;
}

let text = node.text;
if (node.type && node.type !== text && !excludedTypes.has(node.type)) {
text = node.type + ': ' + text;
}

return document.createTextNode(text) as unknown as HTMLElement;
};
}
89 changes: 34 additions & 55 deletions log-viewer/src/features/call-tree/components/CalltreeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ import MinMaxFilter from '../../../tabulator/filters/MinMax.js';
import { progressFormatter } from '../../../tabulator/format/Progress.js';
import { progressFormatterMS } from '../../../tabulator/format/ProgressMS.js';
import * as CommonModules from '../../../tabulator/module/CommonModules.js';
import { Find, formatter } from '../../../tabulator/module/Find.js';
import { Find } from '../../../tabulator/module/Find.js';
import { MiddleRowFocus } from '../../../tabulator/module/MiddleRowFocus.js';
import { RowKeyboardNavigation } from '../../../tabulator/module/RowKeyboardNavigation.js';
import { RowNavigation } from '../../../tabulator/module/RowNavigation.js';
import dataGridStyles from '../../../tabulator/style/DataGrid.scss';
import { createCalltreeNameFormatter } from './CalltreeNameFormatter.js';

// styles
import { globalStyles } from '../../../styles/global.styles.js';
Expand Down Expand Up @@ -79,18 +80,27 @@ export class CalltreeView extends LitElement {
return (this.tableContainer = this.renderRoot?.querySelector('#call-tree-table') ?? null);
}

private _goToRowEvt = ((e: CustomEvent) => {
this._goToRow(e.detail.timestamp);
}) as EventListener;

constructor() {
super();

document.addEventListener('calltree-go-to-row', ((e: CustomEvent) => {
this._goToRow(e.detail.timestamp);
}) as EventListener);

document.addEventListener('calltree-go-to-row', this._goToRowEvt);
document.addEventListener('lv-find', this._findEvt);
document.addEventListener('lv-find-match', this._findEvt);
document.addEventListener('lv-find-close', this._findEvt);
}

disconnectedCallback(): void {
super.disconnectedCallback();
document.removeEventListener('calltree-go-to-row', this._goToRowEvt);
document.removeEventListener('lv-find', this._findEvt);
document.removeEventListener('lv-find-match', this._findEvt);
document.removeEventListener('lv-find-close', this._findEvt);
}

updated(changedProperties: PropertyValues): void {
if (
this.timelineRoot &&
Expand Down Expand Up @@ -397,22 +407,12 @@ export class CalltreeView extends LitElement {
return;
}
this.blockClearHighlights = true;
this.calltreeTable?.blockRedraw();
const currentRow = this.findMap[this.findArgs.count];
const rows = [
currentRow,
this.findMap[this.findArgs.count + 1],
this.findMap[this.findArgs.count - 1],
];
rows.forEach((row) => {
row?.reformat();
//@ts-expect-error This is a custom function added in by Find custom module
await this.calltreeTable.setCurrentMatch(this.findArgs.count, currentRow, {
scrollIfVisible: false,
focusRow: false,
});

if (currentRow) {
//@ts-expect-error This is a custom function added in by RowNavigation custom module
this.calltreeTable.goToRow(currentRow, { scrollIfVisible: false, focusRow: false });
}
this.calltreeTable?.restoreRedraw();
this.blockClearHighlights = false;
}

Expand Down Expand Up @@ -580,7 +580,7 @@ export class CalltreeView extends LitElement {
const excludedTypes = new Set<LogEventType>(['SOQL_EXECUTE_BEGIN', 'DML_BEGIN']);
const governorLimits = rootMethod.governorLimits;

let childIndent;
const nameFormatter = createCalltreeNameFormatter(excludedTypes);
this.calltreeTable = new Tabulator(callTreeTableContainer, {
data: this._toCallTree(rootMethod.children),
layout: 'fitColumns',
Expand Down Expand Up @@ -610,9 +610,6 @@ export class CalltreeView extends LitElement {
return "<div class='sort-by'><div class='sort-by--top'></div><div class='sort-by--bottom'></div></div>";
}
},
rowFormatter: (row: RowComponent) => {
formatter(row, this.findArgs);
},
columnCalcs: 'both',
columnDefaults: {
title: 'default',
Expand All @@ -630,34 +627,7 @@ export class CalltreeView extends LitElement {
return 'Total';
},
cssClass: 'datagrid-textarea datagrid-code-text',
formatter: (cell, _formatterParams, _onRendered) => {
const cellElem = cell.getElement();
const row = cell.getRow();
// @ts-expect-error: _row is private. This is temporary and I will patch the text wrap behaviour in the library.
const dataTree = row._row.modules.dataTree;
const treeLevel = dataTree?.index ?? 0;
childIndent ??= row.getTable().options.dataTreeChildIndent || 0;
const levelIndent = treeLevel * childIndent;
cellElem.style.paddingLeft = `${levelIndent + 4}px`;
cellElem.style.textIndent = `-${levelIndent}px`;

const node = (cell.getData() as CalltreeRow).originalData;
let text = node.text;
if (node.hasValidSymbols) {
const link = document.createElement('a');
link.setAttribute('href', '#!');
link.textContent = text;
return link;
}

if (node.type && !excludedTypes.has(node.type) && node.type !== text) {
text = node.type + ': ' + text;
}

const textSpan = document.createElement('span');
textSpan.textContent = text;
return textSpan;
},
formatter: nameFormatter,
variableHeight: true,
cellClick: (e, cell) => {
const { type } = window.getSelection() ?? {};
Expand Down Expand Up @@ -867,7 +837,14 @@ export class CalltreeView extends LitElement {
this.typeFilterCache.clear();
});

this.calltreeTable.on('renderStarted', () => {
this.calltreeTable.on('dataSorted', () => {
if (!this.blockClearHighlights && this.totalMatches > 0) {
this._resetFindWidget();
this._clearSearchHighlights();
}
});

this.calltreeTable.on('dataFiltered', () => {
if (!this.blockClearHighlights && this.totalMatches > 0) {
this._resetFindWidget();
this._clearSearchHighlights();
Expand Down Expand Up @@ -899,7 +876,7 @@ export class CalltreeView extends LitElement {
this.findArgs.text = '';
this.findArgs.count = 0;
//@ts-expect-error This is a custom function added in by Find custom module
this.calltreeTable.clearFindHighlights(Object.values(this.findMap));
this.calltreeTable.clearFindHighlights();
this.findMap = {};
this.totalMatches = 0;
}
Expand Down Expand Up @@ -983,7 +960,7 @@ export class CalltreeView extends LitElement {
}
}

private _toCallTree(nodes: LogEvent[]): CalltreeRow[] | undefined {
private _toCallTree(nodes: LogEvent[], treeLevel = 0): CalltreeRow[] | undefined {
const len = nodes.length;
if (!len) {
return undefined;
Expand All @@ -995,12 +972,13 @@ export class CalltreeView extends LitElement {
if (!node) {
continue;
}
const children = node.children.length ? this._toCallTree(node.children) : null;
const children = node.children.length ? this._toCallTree(node.children, treeLevel + 1) : null;
results.push({
id: node.timestamp + '-' + i,
originalData: node,
_children: children,
text: node.text,
treeLevel,
namespace: node.namespace,
duration: node.duration,
dmlCount: node.dmlCount,
Expand Down Expand Up @@ -1076,6 +1054,7 @@ interface CalltreeRow {
originalData: LogEvent;
_children: CalltreeRow[] | undefined | null;
text: string;
treeLevel: number;
duration: CountTotals;
namespace: string;
dmlCount: CountTotals;
Expand Down
Loading
Loading