Skip to content

Commit 86d10b4

Browse files
authored
Merge pull request #1550 from github/koesie10/restore-mrva-on-restart
Restore variant analysis view on restart of VSCode
2 parents d3e961f + 7fed5ba commit 86d10b4

File tree

10 files changed

+481
-201
lines changed

10 files changed

+481
-201
lines changed

extensions/ql-vscode/.storybook/preview.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ export const parameters = {
3333
};
3434

3535
(window as any).acquireVsCodeApi = () => ({
36-
postMessage: action('post-vscode-message')
36+
postMessage: action('post-vscode-message'),
37+
setState: action('set-vscode-state'),
3738
});

extensions/ql-vscode/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"onCommand:codeQL.quickQuery",
6464
"onCommand:codeQL.restartQueryServer",
6565
"onWebviewPanel:resultsView",
66+
"onWebviewPanel:codeQL.variantAnalysis",
6667
"onFileSystem:codeql-zip-archive"
6768
],
6869
"main": "./out/extension",

extensions/ql-vscode/src/abstract-webview.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
3333
super();
3434
}
3535

36+
public async restoreView(panel: WebviewPanel): Promise<void> {
37+
this.panel = panel;
38+
this.setupPanel(panel);
39+
}
40+
3641
protected get isShowingPanel() {
3742
return !!this.panel;
3843
}
@@ -59,37 +64,43 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
5964
],
6065
}
6166
);
62-
this.push(
63-
this.panel.onDidDispose(
64-
() => {
65-
this.panel = undefined;
66-
this.panelLoaded = false;
67-
this.onPanelDispose();
68-
},
69-
null,
70-
ctx.subscriptions
71-
)
72-
);
73-
74-
this.panel.webview.html = getHtmlForWebview(
75-
ctx,
76-
this.panel.webview,
77-
config.view,
78-
{
79-
allowInlineStyles: true,
80-
}
81-
);
82-
this.push(
83-
this.panel.webview.onDidReceiveMessage(
84-
async (e) => this.onMessage(e),
85-
undefined,
86-
ctx.subscriptions
87-
)
88-
);
67+
this.setupPanel(this.panel);
8968
}
9069
return this.panel;
9170
}
9271

72+
protected setupPanel(panel: WebviewPanel): void {
73+
const config = this.getPanelConfig();
74+
75+
this.push(
76+
panel.onDidDispose(
77+
() => {
78+
this.panel = undefined;
79+
this.panelLoaded = false;
80+
this.onPanelDispose();
81+
},
82+
null,
83+
this.ctx.subscriptions
84+
)
85+
);
86+
87+
panel.webview.html = getHtmlForWebview(
88+
this.ctx,
89+
panel.webview,
90+
config.view,
91+
{
92+
allowInlineStyles: true,
93+
}
94+
);
95+
this.push(
96+
panel.webview.onDidReceiveMessage(
97+
async (e) => this.onMessage(e),
98+
undefined,
99+
this.ctx.subscriptions
100+
)
101+
);
102+
}
103+
93104
protected abstract getPanelConfig(): WebviewPanelConfig;
94105

95106
protected abstract onPanelDispose(): void;

extensions/ql-vscode/src/extension.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ import { LogScannerService } from './log-insights/log-scanner-service';
104104
import { createInitialQueryInfo } from './run-queries-shared';
105105
import { LegacyQueryRunner } from './legacy-query-server/legacyRunner';
106106
import { QueryRunner } from './queryRunner';
107+
import { VariantAnalysisView } from './remote-queries/variant-analysis-view';
108+
import { VariantAnalysisViewSerializer } from './remote-queries/variant-analysis-view-serializer';
107109
import { VariantAnalysis } from './remote-queries/shared/variant-analysis';
108110
import {
109111
VariantAnalysis as VariantAnalysisApiResponse,
@@ -176,6 +178,7 @@ export interface CodeQLExtensionInterface {
176178
readonly distributionManager: DistributionManager;
177179
readonly databaseManager: DatabaseManager;
178180
readonly databaseUI: DatabaseUI;
181+
readonly variantAnalysisManager: VariantAnalysisManager;
179182
readonly dispose: () => void;
180183
}
181184

@@ -386,14 +389,21 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
386389
allowAutoUpdating: true
387390
})));
388391

389-
return await installOrUpdateThenTryActivate({
392+
const variantAnalysisViewSerializer = new VariantAnalysisViewSerializer(ctx);
393+
Window.registerWebviewPanelSerializer(VariantAnalysisView.viewType, variantAnalysisViewSerializer);
394+
395+
const codeQlExtension = await installOrUpdateThenTryActivate({
390396
isUserInitiated: !!ctx.globalState.get(shouldUpdateOnNextActivationKey),
391397
shouldDisplayMessageWhenNoUpdates: false,
392398

393399
// only auto update on startup if the user has previously requested an update
394400
// otherwise, ask user to accept the update
395401
allowAutoUpdating: !!ctx.globalState.get(shouldUpdateOnNextActivationKey)
396402
});
403+
404+
variantAnalysisViewSerializer.onExtensionLoaded(codeQlExtension.variantAnalysisManager);
405+
406+
return codeQlExtension;
397407
}
398408

399409
async function activateWithInstalledDistribution(
@@ -934,7 +944,10 @@ async function activateWithInstalledDistribution(
934944

935945
ctx.subscriptions.push(
936946
commandRunner('codeQL.mockVariantAnalysisView', async () => {
937-
await variantAnalysisManager.showView(1);
947+
// Generate a random variant analysis ID for testing
948+
const variantAnalysisId: number = Math.floor(Math.random() * 1000000);
949+
950+
await variantAnalysisManager.showView(variantAnalysisId);
938951
})
939952
);
940953

@@ -1159,6 +1172,7 @@ async function activateWithInstalledDistribution(
11591172
distributionManager,
11601173
databaseManager: dbm,
11611174
databaseUI,
1175+
variantAnalysisManager,
11621176
dispose: () => {
11631177
ctx.subscriptions.forEach(d => d.dispose());
11641178
}

extensions/ql-vscode/src/pure/interface-types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,15 @@ export interface SetVariantAnalysisMessage {
440440
variantAnalysis: VariantAnalysis;
441441
}
442442

443+
export type StopVariantAnalysisMessage = {
444+
t: 'stopVariantAnalysis';
445+
variantAnalysisId: number;
446+
}
447+
448+
export type VariantAnalysisState = {
449+
variantAnalysisId: number;
450+
}
451+
443452
export interface SetRepoResultsMessage {
444453
t: 'setRepoResults';
445454
repoResults: VariantAnalysisScannedRepositoryResult[];
@@ -456,4 +465,5 @@ export type ToVariantAnalysisMessage =
456465
| SetRepoStatesMessage;
457466

458467
export type FromVariantAnalysisMessage =
459-
| ViewLoadedMsg;
468+
| ViewLoadedMsg
469+
| StopVariantAnalysisMessage;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { ExtensionContext, WebviewPanel, WebviewPanelSerializer } from 'vscode';
2+
import { VariantAnalysisView } from './variant-analysis-view';
3+
import { VariantAnalysisState } from '../pure/interface-types';
4+
import { VariantAnalysisViewManager } from './variant-analysis-view-manager';
5+
6+
export class VariantAnalysisViewSerializer implements WebviewPanelSerializer {
7+
private resolvePromises: ((value: VariantAnalysisViewManager<VariantAnalysisView>) => void)[] = [];
8+
9+
private manager?: VariantAnalysisViewManager<VariantAnalysisView>;
10+
11+
public constructor(
12+
private readonly ctx: ExtensionContext,
13+
) { }
14+
15+
onExtensionLoaded(manager: VariantAnalysisViewManager<VariantAnalysisView>): void {
16+
this.manager = manager;
17+
18+
this.resolvePromises.forEach((resolve) => resolve(manager));
19+
this.resolvePromises = [];
20+
}
21+
22+
async deserializeWebviewPanel(webviewPanel: WebviewPanel, state: unknown): Promise<void> {
23+
if (!state || typeof state !== 'object') {
24+
return;
25+
}
26+
27+
if (!('variantAnalysisId' in state)) {
28+
return;
29+
}
30+
31+
const variantAnalysisState: VariantAnalysisState = state as VariantAnalysisState;
32+
33+
const manager = await this.waitForExtensionFullyLoaded();
34+
35+
const view = new VariantAnalysisView(this.ctx, variantAnalysisState.variantAnalysisId, manager);
36+
await view.restoreView(webviewPanel);
37+
}
38+
39+
private waitForExtensionFullyLoaded(): Promise<VariantAnalysisViewManager<VariantAnalysisView>> {
40+
if (this.manager) {
41+
return Promise.resolve(this.manager);
42+
}
43+
44+
return new Promise<VariantAnalysisViewManager<VariantAnalysisView>>((resolve) => {
45+
this.resolvePromises.push(resolve);
46+
});
47+
}
48+
}

0 commit comments

Comments
 (0)