Skip to content
Merged
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
46 changes: 34 additions & 12 deletions extensions/ql-vscode/src/abstract-webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ViewColumn,
Uri,
WebviewPanelOptions,
WebviewOptions
WebviewOptions,
} from 'vscode';
import * as path from 'path';

Expand All @@ -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
) {
Expand All @@ -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();
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.panelResolves?.push(resolve);
});
}
this.panelResolves = [];

const config = await this.getPanelConfig();

this.panel = Window.createWebviewPanel(
const panel = Window.createWebviewPanel(
config.viewId,
config.title,
{ viewColumn: config.viewColumn, preserveFocus: config.preserveFocus },
Expand All @@ -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(
() => {
Expand Down Expand Up @@ -101,7 +122,7 @@ export abstract class AbstractWebview<ToMessage extends WebviewMessage, FromMess
);
}

protected abstract getPanelConfig(): WebviewPanelConfig;
protected abstract getPanelConfig(): WebviewPanelConfig | Promise<WebviewPanelConfig>;
Comment thread
koesie10 marked this conversation as resolved.

protected abstract onPanelDispose(): void;

Expand All @@ -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);
}
}
3 changes: 2 additions & 1 deletion extensions/ql-vscode/src/compare/compare-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
Expand Down
20 changes: 13 additions & 7 deletions extensions/ql-vscode/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
languages,
Uri,
window as Window,
env
env, WebviewPanel
} from 'vscode';
import * as cli from './cli';
import { CodeQLCliServer } from './cli';
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 : '');
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -40,6 +41,9 @@ export class VariantAnalysisView extends AbstractWebview<ToVariantAnalysisMessag
t: 'setVariantAnalysis',
variantAnalysis,
});

const panel = await this.getPanel();
panel.title = `${variantAnalysis.query.name} - CodeQL Query Results`;
}

public async updateRepoState(repoState: VariantAnalysisScannedRepositoryState): Promise<void> {
Expand All @@ -64,10 +68,12 @@ export class VariantAnalysisView extends AbstractWebview<ToVariantAnalysisMessag
});
}

protected getPanelConfig(): WebviewPanelConfig {
protected async getPanelConfig(): Promise<WebviewPanelConfig> {
const variantAnalysis = await this.manager.getVariantAnalysis(this.variantAnalysisId);

return {
viewId: VariantAnalysisView.viewType,
title: `CodeQL Query Results for ${this.variantAnalysisId}`,
title: variantAnalysis ? `${variantAnalysis.query.name} - CodeQL Query Results` : `Variant analysis ${this.variantAnalysisId} - CodeQL Query Results`,
viewColumn: ViewColumn.Active,
preserveFocus: true,
view: 'variant-analysis',
Expand Down