Skip to content

Commit 7066440

Browse files
Merge pull request #782 from FishOfPrey/feat-call-tree-theme-coloring
feat(call-tree): apply theme colours to Name column
2 parents c2ad0ee + ea476d9 commit 7066440

11 files changed

Lines changed: 143 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7474
- **Bottom-Up**: Starts from callees and expands to callers, with optional grouping by Namespace or Type.
7575
- **Go to Source**: Click method names to open source from **Time Order**, **Aggregated**, and **Bottom-Up** when symbols are available.
7676
- **Analysis Alignment**: Analysis now uses the same bottom-up table model for consistent caller attribution.
77+
- **🎨 Category Coloring**: The Name column is colored by event category using the active timeline theme — a color chip by default, or a full background tint + colored text when enabled via **Settings → Apex Log Analyzer → colorize Call Tree category names**. ([#734])
7778
- 📄 **Raw Log Navigation**: Seamless navigation between raw log files and the log analysis. ([#204])
7879
- **Show in Raw Log**: Right-click timeline or call tree frames → "Show in Log File" to jump to the corresponding line.
7980
- **Show in Log Analysis**: Click the hover link on raw log lines to navigate back to the log analysis.
@@ -493,6 +494,7 @@ Skipped due to adopting odd numbering for pre releases and even number for relea
493494
[#98]: https://github.com/certinia/debug-log-analyzer/issues/98
494495
[#204]: https://github.com/certinia/debug-log-analyzer/issues/204
495496
[#714]: https://github.com/certinia/debug-log-analyzer/issues/714
497+
[#734]: https://github.com/certinia/debug-log-analyzer/issues/734
496498
[#245]: https://github.com/certinia/debug-log-analyzer/issues/245
497499
[#164]: https://github.com/certinia/debug-log-analyzer/issues/164
498500
[#535]: https://github.com/certinia/debug-log-analyzer/issues/535

lana-docs/docs/docs/features/calltree.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,11 @@ Debug Only and Type filtering are available in **Time Order** and **Aggregated**
6060
### Keyboard Navigation
6161

6262
The Call Tree can be navigated with the keyboard. The up and down keys will move between rows, the left and right keys will expand and collapse a parent within the tree.
63+
64+
### Category Coloring
65+
66+
The Name column is colored by each event's category — Apex, Code Unit, System, Automation, DML, SOQL, Callout and Validation — using the colors of the active timeline theme, so the Call Tree and the [Timeline themes](./timeline.md#themes) stay visually consistent.
67+
68+
By default a small color chip is shown against each row. To color the full cell instead (background tint and colored text), enable **Settings → Apex Log Analyzer → Colorize Call Tree category names**.
69+
70+
Colors follow the active timeline theme and update instantly when you switch themes via **Log: Timeline Theme**.

lana-docs/docs/docs/settings.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ settings.json
5454
}
5555
}
5656
```
57+
58+
## Call Tree category coloring
59+
60+
The Call Tree colors its Name column by event category using the active timeline theme. A color chip is shown by default; enable **Colorize Call Tree category names** under `preferences -> extensions -> Apex Log Analyzer` to tint the whole cell instead. See [Call Tree → Category Coloring](./features/calltree.md#category-coloring).

lana/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@
254254
"markdownDescription": "Enable/ disable the legacy timeline. Default is `false`.",
255255
"order": 2
256256
},
257+
"lana.callTree.categoryColorize": {
258+
"title": "Colorize Call Tree category names",
259+
"type": "boolean",
260+
"default": false,
261+
"markdownDescription": "When enabled, applies a background tint and text color to the Name column in the Call Tree based on the event category, matching the Timeline flame graph colors. When disabled (default), a small color chip is shown instead.",
262+
"order": 2
263+
},
257264
"lana.timeline.colors": {
258265
"type": "object",
259266
"title": "Timeline Event Colors",

lana/src/workspace/AppConfig.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ interface Config {
3333
};
3434
legacy: boolean;
3535
};
36+
callTree: {
37+
categoryColorize: boolean;
38+
};
3639
}
3740

3841
export function getConfig(): Config {

log-viewer/src/features/call-tree/components/AggregatedTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export function createAggregatedTable(
5858
headerSortElement,
5959
columnCalcs: 'both',
6060
columnDefaults: commonColumnDefaults,
61+
rowFormatter: callbacks.rowFormatter,
6162
columns: [
6263
{
6364
title: 'Name',

log-viewer/src/features/call-tree/components/BottomUpTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export function createBottomUpTable(
118118
groupStartOpen: false,
119119
groupToggleElement: 'header',
120120
columnDefaults: commonColumnDefaults,
121+
rowFormatter: callbacks.rowFormatter,
121122
} as Options;
122123

123124
const table = new Tabulator(container, {

log-viewer/src/features/call-tree/components/CalltreeView.ts

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ import type { RowComponent, Tabulator } from 'tabulator-tables';
1515

1616
import type { ApexLog, LogEvent } from 'apex-log-parser';
1717
import { eventBus } from '../../../core/events/EventBus.js';
18-
import { vscodeMessenger } from '../../../core/messaging/VSCodeExtensionMessenger.js';
18+
import {
19+
VSCodeExtensionMessenger,
20+
vscodeMessenger,
21+
} from '../../../core/messaging/VSCodeExtensionMessenger.js';
1922
import { findEventByEventIndex } from '../../../core/utility/EventSearch.js';
2023
import { isVisible } from '../../../core/utility/Util.js';
24+
import { getSettings } from '../../settings/Settings.js';
25+
import { DEFAULT_THEME_NAME } from '../../timeline/themes/Themes.js';
26+
import { addCustomThemes, getTheme } from '../../timeline/themes/ThemeSelector.js';
2127
import type { AggregatedRow, BottomUpRow } from '../utils/Aggregation.js';
2228
import { deepFilter } from '../utils/DetailsFilter.js';
2329
import { expandCollapseAll } from '../utils/ExpandCollapse.js';
@@ -121,6 +127,49 @@ export class CalltreeView extends LitElement {
121127
document.addEventListener('lv-find-close', this._findEvt);
122128
}
123129

130+
override connectedCallback(): void {
131+
super.connectedCallback();
132+
this._applyTheme(DEFAULT_THEME_NAME);
133+
134+
VSCodeExtensionMessenger.listen<{ activeTheme: string }>((event) => {
135+
const { cmd, payload } = event.data;
136+
if (cmd === 'switchTimelineTheme') {
137+
this._applyTheme(payload.activeTheme ?? DEFAULT_THEME_NAME);
138+
}
139+
});
140+
141+
getSettings().then((settings) => {
142+
const { timeline, callTree } = settings;
143+
addCustomThemes(timeline.customThemes);
144+
this._applyTheme(timeline.activeTheme ?? DEFAULT_THEME_NAME);
145+
this._setCategoryColorize(callTree?.categoryColorize ?? false);
146+
});
147+
}
148+
149+
private _applyTheme(themeName: string): void {
150+
const theme = getTheme(themeName);
151+
this.style.setProperty('--ct-color-apex', theme.apex);
152+
this.style.setProperty('--ct-color-code-unit', theme.codeUnit);
153+
this.style.setProperty('--ct-color-system', theme.system);
154+
this.style.setProperty('--ct-color-automation', theme.automation);
155+
this.style.setProperty('--ct-color-dml', theme.dml);
156+
this.style.setProperty('--ct-color-soql', theme.soql);
157+
this.style.setProperty('--ct-color-callout', theme.callout);
158+
this.style.setProperty('--ct-color-validation', theme.validation);
159+
}
160+
161+
private _setCategoryColorize(enabled: boolean): void {
162+
this.classList.toggle('category-colorize', enabled);
163+
}
164+
165+
private _rowFormatter = (row: RowComponent): void => {
166+
const data = row.getData() as { originalData?: { category?: string } };
167+
const category = data.originalData?.category;
168+
if (category) {
169+
row.getElement().classList.add(`row-cat-${category.toLowerCase().replace(' ', '-')}`);
170+
}
171+
};
172+
124173
disconnectedCallback(): void {
125174
super.disconnectedCallback();
126175
document.removeEventListener('calltree-go-to-row', this._goToRowEvt);
@@ -259,6 +308,64 @@ export class CalltreeView extends LitElement {
259308
opacity: 0;
260309
pointer-events: none;
261310
}
311+
312+
.tabulator-row.row-cat-apex .datagrid-code-text {
313+
border-left: 6px solid var(--ct-color-apex);
314+
}
315+
.tabulator-row.row-cat-code-unit .datagrid-code-text {
316+
border-left: 6px solid var(--ct-color-code-unit);
317+
}
318+
.tabulator-row.row-cat-system .datagrid-code-text {
319+
border-left: 6px solid var(--ct-color-system);
320+
}
321+
.tabulator-row.row-cat-automation .datagrid-code-text {
322+
border-left: 6px solid var(--ct-color-automation);
323+
}
324+
.tabulator-row.row-cat-dml .datagrid-code-text {
325+
border-left: 6px solid var(--ct-color-dml);
326+
}
327+
.tabulator-row.row-cat-soql .datagrid-code-text {
328+
border-left: 6px solid var(--ct-color-soql);
329+
}
330+
.tabulator-row.row-cat-callout .datagrid-code-text {
331+
border-left: 6px solid var(--ct-color-callout);
332+
}
333+
.tabulator-row.row-cat-validation .datagrid-code-text {
334+
border-left: 6px solid var(--ct-color-validation);
335+
}
336+
337+
:host(.category-colorize) .tabulator-row.row-cat-apex .datagrid-code-text {
338+
background-color: color-mix(in srgb, var(--ct-color-apex) 10%, transparent);
339+
color: var(--ct-color-apex);
340+
}
341+
:host(.category-colorize) .tabulator-row.row-cat-code-unit .datagrid-code-text {
342+
background-color: color-mix(in srgb, var(--ct-color-code-unit) 10%, transparent);
343+
color: var(--ct-color-code-unit);
344+
}
345+
:host(.category-colorize) .tabulator-row.row-cat-system .datagrid-code-text {
346+
background-color: color-mix(in srgb, var(--ct-color-system) 10%, transparent);
347+
color: var(--ct-color-system);
348+
}
349+
:host(.category-colorize) .tabulator-row.row-cat-automation .datagrid-code-text {
350+
background-color: color-mix(in srgb, var(--ct-color-automation) 10%, transparent);
351+
color: var(--ct-color-automation);
352+
}
353+
:host(.category-colorize) .tabulator-row.row-cat-dml .datagrid-code-text {
354+
background-color: color-mix(in srgb, var(--ct-color-dml) 10%, transparent);
355+
color: var(--ct-color-dml);
356+
}
357+
:host(.category-colorize) .tabulator-row.row-cat-soql .datagrid-code-text {
358+
background-color: color-mix(in srgb, var(--ct-color-soql) 10%, transparent);
359+
color: var(--ct-color-soql);
360+
}
361+
:host(.category-colorize) .tabulator-row.row-cat-callout .datagrid-code-text {
362+
background-color: color-mix(in srgb, var(--ct-color-callout) 10%, transparent);
363+
color: var(--ct-color-callout);
364+
}
365+
:host(.category-colorize) .tabulator-row.row-cat-validation .datagrid-code-text {
366+
background-color: color-mix(in srgb, var(--ct-color-validation) 10%, transparent);
367+
color: var(--ct-color-validation);
368+
}
262369
`,
263370
];
264371

@@ -715,6 +822,7 @@ export class CalltreeView extends LitElement {
715822
const mouseEvent = e as MouseEvent;
716823
this._showRowContextMenu(row, mouseEvent.clientX, mouseEvent.clientY);
717824
},
825+
rowFormatter: this._rowFormatter,
718826
});
719827
this.calltreeTable = table;
720828
await tableBuilt;
@@ -742,6 +850,7 @@ export class CalltreeView extends LitElement {
742850
this._clearSearchHighlights();
743851
}
744852
},
853+
rowFormatter: this._rowFormatter,
745854
});
746855
this.aggregatedTreeTable = table;
747856
await tableBuilt;
@@ -765,6 +874,7 @@ export class CalltreeView extends LitElement {
765874
this._clearSearchHighlights();
766875
}
767876
},
877+
rowFormatter: this._rowFormatter,
768878
},
769879
{
770880
selectableRows: 'highlight',

log-viewer/src/features/call-tree/components/TableShared.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Copyright (c) 2025 Certinia Inc. All rights reserved.
33
*/
4-
import { Tabulator } from 'tabulator-tables';
4+
import { Tabulator, type RowComponent } from 'tabulator-tables';
55

66
import * as CommonModules from '../../../tabulator/module/CommonModules.js';
77
import { Find } from '../../../tabulator/module/Find.js';
@@ -20,6 +20,7 @@ export interface TableCallbacks {
2020
) => boolean;
2121
onFilterCacheClear?: () => void;
2222
onRenderStarted: () => void;
23+
rowFormatter?: (row: RowComponent) => void;
2324
}
2425

2526
export function registerTableModules(): void {

log-viewer/src/features/call-tree/components/TimeOrderTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export function createTimeOrderTable(
6666
headerSortElement,
6767
columnCalcs: 'both',
6868
columnDefaults: commonColumnDefaults,
69+
rowFormatter: callbacks.rowFormatter,
6970
columns: [
7071
{
7172
title: 'Name',

0 commit comments

Comments
 (0)