Skip to content

Commit 9b4594f

Browse files
committed
Implemented external API
This commit provides an external API that can be used by other extensions to communicate with the base trace extension. The current API provides a way to retrieve the active experiment as well as fire events and register callbacks. This is the initial API and will be further expanded in future commits. Fixes #140 Signed-off-by: Neel Gondalia <ngondalia@blackberry.com>
1 parent f029c45 commit 9b4594f

File tree

8 files changed

+199
-2
lines changed

8 files changed

+199
-2
lines changed

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,45 @@ yarn playwright test --retries <retries>
215215
[vscode-messages]: https://code.visualstudio.com/api/extension-guides/webview#passing-messages-from-an-extension-to-a-webview
216216
[vscode-webview]: https://github.com/rebornix/vscode-webview-react
217217
[vscode-webview-react]: https://github.com/rebornix/vscode-webview-react
218+
219+
## Using the External API
220+
221+
VSCode Trace Extension provides an external API that adopter extensions can rely on for communication. Currently the API is limited to the following:
222+
223+
```javascript
224+
getActiveExperiment(): Experiment | undefined,
225+
getActiveWebviewPanels(): { [key: string]: TraceViewerPanel | undefined; },
226+
getActiveWebviews(): vscode.WebviewView[],
227+
onWebviewCreated(listener: (data: vscode.WebviewView) => void): void,
228+
onWebviewPanelCreated(listener: (data: vscode.WebviewPanel) => void): void,
229+
```
230+
231+
### Using the API from Adopter Extensions
232+
```javascript
233+
//The following retrieves the API object from the vscode-trace-extension
234+
const ext = vscode.extensions.getExtension("tracecompass-community.vscode-trace-extension");
235+
const importedApi = ext.exports;
236+
```
237+
Once you have the API object, you can proceed to make API calls. For example, if you wish to retrieve the active experiment in the Trace Viewer, the following API call can be used:
238+
```javascript
239+
const experiment = importedApi.getActiveExperiment();
240+
```
241+
242+
The API provides getters to retrieve the active webviews and panels. This can be useful for scenarios when webviews/panels were created before the adopter extension was activated but the adopter exension still wants to handle messages from them. The API also provides a way to attach a listener for when webview or webview panel is created.
243+
```javascript
244+
importedApi.onWebviewPanelCreated(_panel => {
245+
// For newly created panel, handle messages from webviews
246+
_panel.webview.onDidReceiveMessage((message) => {
247+
switch (message.command) {
248+
case "experimentSelected":
249+
console.log("From adopter extension - experiment selected: " + message.data);
250+
break;
251+
default:
252+
break;
253+
}
254+
});
255+
_panel.onDidDispose(() => {
256+
console.log("panel disposed");
257+
});
258+
});
259+
```

vscode-trace-extension/src/extension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ import { fileHandler, openOverviewHandler, resetZoomHandler, undoRedoHandler, zo
88
import { TraceServerConnectionStatusService } from './utils/trace-server-status';
99
import { getTspClientUrl, updateTspClient } from './utils/tspClient';
1010
import { TraceExtensionLogger } from './utils/trace-extension-logger';
11+
import { ExternalAPI, traceExtensionAPI} from './external-api/external-api';
12+
import { TraceExtensionWebviewManager } from './utils/trace-extension-webview-manager';
1113
import { VSCODE_MESSAGES } from 'vscode-trace-common/lib/messages/vscode-message-manager';
1214
import { TraceViewerPanel } from './trace-viewer-panel/trace-viewer-webview-panel';
1315
import { TspClientProvider } from 'vscode-trace-common/lib/client/tsp-client-provider-impl';
1416

1517
export let traceLogger: TraceExtensionLogger;
18+
export const traceExtensionWebviewManager: TraceExtensionWebviewManager = new TraceExtensionWebviewManager();
1619
const tspClientProvider = new TspClientProvider(getTspClientUrl(), undefined);
1720

18-
export function activate(context: vscode.ExtensionContext): void {
21+
export function activate(context: vscode.ExtensionContext): ExternalAPI {
1922
traceLogger = new TraceExtensionLogger('Trace Extension');
2023

2124
const serverStatusBarItemPriority = 1;
@@ -117,10 +120,12 @@ export function activate(context: vscode.ExtensionContext): void {
117120

118121
vscode.commands.executeCommand('setContext', 'traceViewer.markerSetsPresent', false);
119122
vscode.commands.executeCommand('setContext', 'traceViewer.markerCategoriesPresent', false);
123+
return traceExtensionAPI;
120124
}
121125

122126
export function deactivate(): void {
123127
traceLogger.disposeChannel();
128+
traceExtensionWebviewManager.dispose();
124129
}
125130

126131
async function startTraceServerIfAvailable(): Promise<void> {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/***************************************************************************************
2+
* Copyright (c) 2023 BlackBerry Limited and others.
3+
*
4+
* Licensed under the MIT license. See LICENSE file in the project root for details.
5+
***************************************************************************************/
6+
import { Experiment } from 'tsp-typescript-client/lib/models/experiment';
7+
import { TraceViewerPanel } from '../trace-viewer-panel/trace-viewer-webview-panel';
8+
import * as vscode from 'vscode';
9+
import { traceExtensionWebviewManager } from '../extension';
10+
11+
export interface ExternalAPI {
12+
getActiveExperiment(): Experiment | undefined,
13+
getActiveWebviewPanels(): { [key: string]: TraceViewerPanel | undefined; },
14+
getActiveWebviews(): vscode.WebviewView[],
15+
onWebviewCreated(listener: (data: vscode.WebviewView) => void): void,
16+
onWebviewPanelCreated(listener: (data: vscode.WebviewPanel) => void): void,
17+
}
18+
19+
export const traceExtensionAPI: ExternalAPI = {
20+
/**
21+
* Retrieves the currently active experiement
22+
*
23+
* @returns Experiment if one is currently active, otherwise undefined
24+
*/
25+
getActiveExperiment(): Experiment | undefined {
26+
return TraceViewerPanel.getCurrentExperiment();
27+
},
28+
/**
29+
* Retrieves active trace panels
30+
*
31+
* @returns Active panels
32+
*/
33+
getActiveWebviewPanels(): { [key: string]: TraceViewerPanel | undefined; } {
34+
return TraceViewerPanel.activePanels;
35+
},
36+
/**
37+
* Retrieves active webviews
38+
*
39+
* @returns list of active webviews
40+
*/
41+
getActiveWebviews(): vscode.WebviewView[] {
42+
return traceExtensionWebviewManager.getAllActiveWebviews();
43+
},
44+
/**
45+
* Registers an event listener for onWebviewCreated event
46+
*
47+
* @param listener event listener
48+
*/
49+
onWebviewCreated(listener: (data: vscode.WebviewView) => void): void {
50+
traceExtensionWebviewManager.onWebviewCreated(listener);
51+
},
52+
/**
53+
* Registers an event listener for onWebviewPanelCreated event
54+
*
55+
* @param listener event listener
56+
*/
57+
onWebviewPanelCreated(listener: (data: vscode.WebviewPanel) => void): void {
58+
traceExtensionWebviewManager.onWebviewPanelCreated(listener);
59+
}
60+
};

vscode-trace-extension/src/trace-explorer/available-views/trace-explorer-available-views-webview-provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TraceServerConnectionStatusService } from '../../utils/trace-server-sta
88
import { getTraceServerUrl, getTspClientUrl } from '../../utils/tspClient';
99
import { convertSignalExperiment } from 'vscode-trace-common/lib/signals/vscode-signal-converter';
1010
import { VSCODE_MESSAGES } from 'vscode-trace-common/lib/messages/vscode-message-manager';
11+
import { traceExtensionWebviewManager } from 'vscode-trace-extension/src/extension';
1112

1213
const JSONBig = JSONBigConfig({
1314
useNativeBigInt: true,
@@ -47,6 +48,7 @@ export class TraceExplorerAvailableViewsProvider implements vscode.WebviewViewPr
4748
};
4849

4950
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
51+
traceExtensionWebviewManager.fireWebviewCreated(webviewView);
5052

5153
// Handle messages from the webview
5254
webviewView.webview.onDidReceiveMessage(message => {

vscode-trace-extension/src/trace-explorer/opened-traces/trace-explorer-opened-traces-webview-provider.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { TraceViewerPanel } from '../../trace-viewer-panel/trace-viewer-webview-
77
import { TraceServerConnectionStatusService } from '../../utils/trace-server-status';
88
import { getTraceServerUrl, getTspClientUrl } from '../../utils/tspClient';
99
import { VSCODE_MESSAGES } from 'vscode-trace-common/lib/messages/vscode-message-manager';
10+
import { traceExtensionWebviewManager } from 'vscode-trace-extension/src/extension';
1011

1112
const JSONBig = JSONBigConfig({
1213
useNativeBigInt: true,
@@ -20,7 +21,7 @@ export class TraceExplorerOpenedTracesViewProvider implements vscode.WebviewView
2021
private _disposables: vscode.Disposable[] = [];
2122
private _selectedExperiment: Experiment | undefined;
2223

23-
constructor(
24+
constructor(
2425
private readonly _extensionUri: vscode.Uri,
2526
private readonly _statusService: TraceServerConnectionStatusService,
2627
) {}
@@ -69,6 +70,7 @@ export class TraceExplorerOpenedTracesViewProvider implements vscode.WebviewView
6970
};
7071

7172
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
73+
traceExtensionWebviewManager.fireWebviewCreated(webviewView);
7274

7375
// Handle messages from the webview
7476
webviewView.webview.onDidReceiveMessage(message => {

vscode-trace-extension/src/trace-explorer/properties/trace-explorer-properties-view-webview-provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Licensed under the MIT license. See LICENSE file in the project root for details.
55
***************************************************************************************/
66
import * as vscode from 'vscode';
7+
import { traceExtensionWebviewManager } from 'vscode-trace-extension/src/extension';
78
import { getTraceServerUrl } from 'vscode-trace-extension/src/utils/tspClient';
89

910
export class TraceExplorerItemPropertiesProvider implements vscode.WebviewViewProvider {
@@ -26,6 +27,7 @@ export class TraceExplorerItemPropertiesProvider implements vscode.WebviewViewPr
2627
]
2728
};
2829
webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
30+
traceExtensionWebviewManager.fireWebviewCreated(webviewView);
2931
}
3032

3133
postMessagetoWebview(_command: string, _data: unknown): void {

vscode-trace-extension/src/trace-viewer-panel/trace-viewer-webview-panel.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { VSCODE_MESSAGES } from 'vscode-trace-common/lib/messages/vscode-message
99
import { MarkerSet } from 'tsp-typescript-client/lib/models/markerset';
1010
import JSONBigConfig from 'json-bigint';
1111
import * as fs from 'fs';
12+
import { traceExtensionWebviewManager } from '../extension';
1213

1314
const JSONBig = JSONBigConfig({
1415
useNativeBigInt: true,
@@ -99,6 +100,10 @@ export class TraceViewerPanel {
99100
TraceViewerPanel.currentPanel?.showMarkersFilter();
100101
}
101102

103+
public static getCurrentExperiment(): Experiment | undefined {
104+
return TraceViewerPanel.currentPanel?._experiment;
105+
}
106+
102107
private static async saveTraceCsv(csvData: string, defaultFileName: string) {
103108
const saveDialogOptions = {
104109
defaultUri: vscode.workspace.workspaceFolders
@@ -143,6 +148,7 @@ export class TraceViewerPanel {
143148

144149
// Set the webview's initial html content
145150
this._panel.webview.html = this._getHtmlForWebview();
151+
traceExtensionWebviewManager.fireWebviewPanelCreated(this._panel);
146152

147153
// Listen for when the panel is disposed
148154
// This happens when the user closes the panel or when the panel is closed programmatically
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/***************************************************************************************
2+
* Copyright (c) 2023 BlackBerry Limited and others.
3+
*
4+
* Licensed under the MIT license. See LICENSE file in the project root for details.
5+
***************************************************************************************/
6+
import * as vscode from 'vscode';
7+
8+
/**
9+
* Manages webview panels and webviews creation events
10+
*/
11+
export class TraceExtensionWebviewManager {
12+
private webviews: vscode.WebviewView[] = [];
13+
private webviewCreated: vscode.EventEmitter<vscode.WebviewView> = new vscode.EventEmitter();
14+
private webviewPanelCreated: vscode.EventEmitter<vscode.WebviewPanel> = new vscode.EventEmitter();
15+
private isManagerDisposed = false;
16+
17+
getAllActiveWebviews(): vscode.WebviewView[] {
18+
if (!this.isDisposed()) {
19+
return this.webviews;
20+
}
21+
return [];
22+
}
23+
24+
fireWebviewCreated(_webview: vscode.WebviewView): void {
25+
if (!this.isDisposed()) {
26+
this.webviewCreated.fire(_webview);
27+
this.addWebview(_webview);
28+
}
29+
}
30+
31+
fireWebviewPanelCreated(_webviewPanel: vscode.WebviewPanel): void {
32+
if (!this.isDisposed()) {
33+
this.webviewPanelCreated.fire(_webviewPanel);
34+
}
35+
}
36+
37+
onWebviewCreated(listener: (data: vscode.WebviewView) => unknown): void {
38+
if (!this.isDisposed()) {
39+
this.webviewCreated.event(listener);
40+
}
41+
}
42+
43+
onWebviewPanelCreated(listener: (data: vscode.WebviewPanel) => unknown): void {
44+
if (!this.isDisposed()) {
45+
this.webviewPanelCreated.event(listener);
46+
}
47+
}
48+
49+
dispose(): void {
50+
if (!this.isDisposed()) {
51+
this.webviews = [];
52+
this.webviewCreated.dispose();
53+
this.webviewPanelCreated.dispose();
54+
this.isManagerDisposed = true;
55+
}
56+
}
57+
58+
isDisposed(): boolean {
59+
return this.isManagerDisposed;
60+
}
61+
62+
private addWebview(webview: vscode.WebviewView): void {
63+
// Remove it from the array when the webview disposes
64+
webview.onDidDispose(() => {
65+
this.removeWebview(webview);
66+
});
67+
this.webviews.push(webview);
68+
}
69+
70+
private removeWebview(_webview: vscode.WebviewView): void {
71+
this.webviews.filter(webview => webview === _webview).forEach(webview => {
72+
const index = this.webviews.indexOf(webview);
73+
if (index !== -1) {
74+
this.webviews.splice(index, 1);
75+
}
76+
});
77+
}
78+
}

0 commit comments

Comments
 (0)