Make webview panel creation async

This will make the creation of a webview panel async to allow the
`getPanelConfig` method to be an async function. This will allow us to
do some work (like retrieving the variant analysis) in the
`getPanelConfig` method.
This commit is contained in:
Koen Vlaswinkel
2022-10-31 11:34:58 +01:00
parent c36ce4867e
commit cdbdf62612
5 changed files with 53 additions and 22 deletions

View File

@@ -5,7 +5,7 @@ import {
ViewColumn,
Uri,
WebviewPanelOptions,
WebviewOptions
WebviewOptions,
} from 'vscode';
import * as path from 'path';
@@ -27,6 +27,8 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
protected panelLoaded = false;
protected panelLoadedCallBacks: (() => void)[] = [];
private panelResolves?: Array<(panel: WebviewPanel) => void>;
constructor(
protected readonly ctx: ExtensionContext
) {
@@ -35,20 +37,36 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
public async restoreView(panel: WebviewPanel): Promise<void> {
this.panel = panel;
this.setupPanel(panel);
const config = await this.getPanelConfig();
await this.setupPanel(panel, config);
}
protected get isShowingPanel() {
return !!this.panel;
}
protected getPanel(): WebviewPanel {
protected async getPanel(): Promise<WebviewPanel> {
if (this.panel == undefined) {
const { ctx } = this;
const config = this.getPanelConfig();
// This is an async method, so in theory this method can be called concurrently. To ensure that we don't
// create two panels, we use a promise that resolves when the panel is created. This way, if the panel is
// being created, the promise will resolve when it is done.
if (this.panelResolves !== undefined) {
return new Promise((resolve) => {
if (this.panel !== undefined) {
resolve(this.panel);
return;
}
this.panel = Window.createWebviewPanel(
this.panelResolves?.push(resolve);
});
}
this.panelResolves = [];
const config = await this.getPanelConfig();
const panel = Window.createWebviewPanel(
config.viewId,
config.title,
{ viewColumn: config.viewColumn, preserveFocus: config.preserveFocus },
@@ -64,14 +82,17 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
],
}
);
this.setupPanel(this.panel);
this.panel = panel;
this.setupPanel(panel, config);
this.panelResolves.forEach((resolve) => resolve(panel));
this.panelResolves = undefined;
}
return this.panel;
}
protected setupPanel(panel: WebviewPanel): void {
const config = this.getPanelConfig();
protected setupPanel(panel: WebviewPanel, config: WebviewPanelConfig): void {
this.push(
panel.onDidDispose(
() => {
@@ -101,7 +122,7 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
);
}
protected abstract getPanelConfig(): WebviewPanelConfig;
protected abstract getPanelConfig(): WebviewPanelConfig | Promise<WebviewPanelConfig>;
protected abstract onPanelDispose(): void;
@@ -123,7 +144,8 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
this.panelLoadedCallBacks = [];
}
protected postMessage(msg: ToMessage): Thenable<boolean> {
return this.getPanel().webview.postMessage(msg);
protected async postMessage(msg: ToMessage): Promise<boolean> {
const panel = await this.getPanel();
return panel.webview.postMessage(msg);
}
}

View File

@@ -46,7 +46,8 @@ export class CompareView extends AbstractWebview<ToCompareViewMessage, FromCompa
selectedResultSetName?: string
) {
this.comparePair = { from, to };
this.getPanel().reveal(undefined, true);
const panel = await this.getPanel();
panel.reveal(undefined, true);
await this.waitForPanelLoaded();
const [

View File

@@ -7,7 +7,7 @@ import {
languages,
Uri,
window as Window,
env
env, WebviewPanel
} from 'vscode';
import * as cli from './cli';
import { CodeQLCliServer } from './cli';
@@ -341,6 +341,8 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
return;
}
const panel = await this.getPanel();
this._interpretation = undefined;
const interpretationPage = await this.interpretResultsInfo(
fullQuery.completedQuery.query,
@@ -350,12 +352,11 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
const sortedResultsMap: SortedResultsMap = {};
Object.entries(fullQuery.completedQuery.sortedResultsInfo).forEach(
([k, v]) =>
(sortedResultsMap[k] = this.convertPathPropertiesToWebviewUris(v))
(sortedResultsMap[k] = this.convertPathPropertiesToWebviewUris(panel, v))
);
this._displayedQuery = fullQuery;
const panel = this.getPanel();
await this.waitForPanelLoaded();
if (!panel.visible) {
if (forceReveal === WebviewReveal.Forced) {
@@ -426,6 +427,7 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
interpretation: interpretationPage,
origResultsPaths: fullQuery.completedQuery.query.resultsPaths,
resultsPath: this.convertPathToWebviewUri(
panel,
fullQuery.completedQuery.query.resultsPaths.resultsPath
),
parsedResultSets,
@@ -498,10 +500,12 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
throw new Error('trying to view a page of a query that is not loaded');
}
const panel = await this.getPanel();
const sortedResultsMap: SortedResultsMap = {};
Object.entries(results.completedQuery.sortedResultsInfo).forEach(
([k, v]) =>
(sortedResultsMap[k] = this.convertPathPropertiesToWebviewUris(v))
(sortedResultsMap[k] = this.convertPathPropertiesToWebviewUris(panel, v))
);
const resultSetSchemas = await this.getResultSetSchemas(results.completedQuery, sorted ? selectedTable : '');
@@ -544,6 +548,7 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
interpretation: this._interpretation,
origResultsPaths: results.completedQuery.query.resultsPaths,
resultsPath: this.convertPathToWebviewUri(
panel,
results.completedQuery.query.resultsPaths.resultsPath
),
parsedResultSets,
@@ -812,15 +817,16 @@ export class ResultsView extends AbstractWebview<IntoResultsViewMsg, FromResults
this._diagnosticCollection.set(diagnostics);
}
private convertPathToWebviewUri(path: string): string {
return fileUriToWebviewUri(this.getPanel(), Uri.file(path));
private convertPathToWebviewUri(panel: WebviewPanel, path: string): string {
return fileUriToWebviewUri(panel, Uri.file(path));
}
private convertPathPropertiesToWebviewUris(
panel: WebviewPanel,
info: SortedResultSetInfo
): SortedResultSetInfo {
return {
resultsPath: this.convertPathToWebviewUri(info.resultsPath),
resultsPath: this.convertPathToWebviewUri(panel, info.resultsPath),
sortState: info.sortState,
};
}

View File

@@ -49,7 +49,8 @@ export class RemoteQueriesView extends AbstractWebview<ToRemoteQueriesMessage, F
}
async showResults(query: RemoteQuery, queryResult: RemoteQueryResult) {
this.getPanel().reveal(undefined, true);
const panel = await this.getPanel();
panel.reveal(undefined, true);
await this.waitForPanelLoaded();
const model = this.buildViewModel(query, queryResult);

View File

@@ -26,7 +26,8 @@ export class VariantAnalysisView extends AbstractWebview<ToVariantAnalysisMessag
}
public async openView() {
this.getPanel().reveal(undefined, true);
const panel = await this.getPanel();
panel.reveal(undefined, true);
await this.waitForPanelLoaded();
}