Merge pull request #2813 from github/koesie10/use-app-in-webview

Use `App` instead of `ExtensionContext` for webviews
This commit is contained in:
Koen Vlaswinkel
2023-09-15 10:12:34 +02:00
committed by GitHub
15 changed files with 57 additions and 83 deletions

View File

@@ -1,6 +1,5 @@
import {
WebviewPanel,
ExtensionContext,
window as Window,
ViewColumn,
Uri,
@@ -9,6 +8,7 @@ import {
} from "vscode";
import { join } from "path";
import { App } from "../app";
import { DisposableObject, DisposeHandler } from "../disposable-object";
import { tmpDir } from "../../tmp-dir";
import { getHtmlForWebview, WebviewMessage, WebviewKind } from "./webview-html";
@@ -34,7 +34,7 @@ export abstract class AbstractWebview<
private panelResolves?: Array<(panel: WebviewPanel) => void>;
constructor(protected readonly ctx: ExtensionContext) {
constructor(protected readonly app: App) {
super();
}
@@ -50,8 +50,6 @@ export abstract class AbstractWebview<
protected async getPanel(): Promise<WebviewPanel> {
if (this.panel === undefined) {
const { ctx } = this;
// 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.
@@ -81,7 +79,7 @@ export abstract class AbstractWebview<
localResourceRoots: [
...(config.additionalOptions?.localResourceRoots ?? []),
Uri.file(tmpDir.name),
Uri.file(join(ctx.extensionPath, "out")),
Uri.file(join(this.app.extensionPath, "out")),
],
},
);
@@ -99,19 +97,15 @@ export abstract class AbstractWebview<
protected setupPanel(panel: WebviewPanel, config: WebviewPanelConfig): void {
this.push(
panel.onDidDispose(
() => {
this.panel = undefined;
this.panelLoaded = false;
this.onPanelDispose();
},
null,
this.ctx.subscriptions,
),
panel.onDidDispose(() => {
this.panel = undefined;
this.panelLoaded = false;
this.onPanelDispose();
}, null),
);
panel.webview.html = getHtmlForWebview(
this.ctx,
this.app,
panel.webview,
config.view,
{
@@ -123,7 +117,6 @@ export abstract class AbstractWebview<
panel.webview.onDidReceiveMessage(
async (e) => this.onMessage(e),
undefined,
this.ctx.subscriptions,
),
);
}

View File

@@ -1,6 +1,7 @@
import { ExtensionContext, Uri, Webview } from "vscode";
import { Uri, Webview } from "vscode";
import { randomBytes } from "crypto";
import { EOL } from "os";
import { App } from "../app";
export type WebviewKind =
| "results"
@@ -19,7 +20,7 @@ export interface WebviewMessage {
* Uses a content security policy that only loads the given script.
*/
export function getHtmlForWebview(
ctx: ExtensionContext,
app: App,
webview: Webview,
view: WebviewKind,
{
@@ -33,10 +34,13 @@ export function getHtmlForWebview(
allowWasmEval: false,
},
): string {
const scriptUriOnDisk = Uri.file(ctx.asAbsolutePath("out/webview.js"));
const scriptUriOnDisk = Uri.joinPath(
Uri.file(app.extensionPath),
"out/webview.js",
);
const stylesheetUrisOnDisk = [
Uri.file(ctx.asAbsolutePath("out/webview.css")),
Uri.joinPath(Uri.file(app.extensionPath), "out/webview.css"),
];
// Convert the on-disk URIs into webview URIs.

View File

@@ -1,4 +1,4 @@
import { ExtensionContext, ViewColumn } from "vscode";
import { ViewColumn } from "vscode";
import {
FromCompareViewMessage,
@@ -25,6 +25,7 @@ import {
} from "../common/vscode/abstract-webview";
import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../common/errors";
import { App } from "../common/app";
interface ComparePair {
from: CompletedLocalQueryInfo;
@@ -38,7 +39,7 @@ export class CompareView extends AbstractWebview<
private comparePair: ComparePair | undefined;
constructor(
ctx: ExtensionContext,
app: App,
private databaseManager: DatabaseManager,
private cliServer: CodeQLCliServer,
private logger: Logger,
@@ -47,7 +48,7 @@ export class CompareView extends AbstractWebview<
item: CompletedLocalQueryInfo,
) => Promise<void>,
) {
super(ctx);
super(app);
}
async showResults(

View File

@@ -396,10 +396,7 @@ export async function activate(
),
);
const variantAnalysisViewSerializer = new VariantAnalysisViewSerializer(
ctx,
app,
);
const variantAnalysisViewSerializer = new VariantAnalysisViewSerializer(app);
Window.registerWebviewPanelSerializer(
VariantAnalysisView.viewType,
variantAnalysisViewSerializer,
@@ -813,7 +810,7 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing results panel interface.");
const localQueryResultsView = new ResultsView(
ctx,
app,
dbm,
cliServer,
queryServerLogger,
@@ -836,7 +833,6 @@ async function activateWithInstalledDistribution(
);
const variantAnalysisManager = new VariantAnalysisManager(
ctx,
app,
cliServer,
variantAnalysisStorageDir,
@@ -888,7 +884,7 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing compare view.");
const compareView = new CompareView(
ctx,
app,
dbm,
cliServer,
queryServerLogger,
@@ -935,7 +931,6 @@ async function activateWithInstalledDistribution(
ctx.subscriptions.push(debuggerUI);
const modelEditorModule = await ModelEditorModule.initialize(
ctx,
app,
dbm,
cliServer,

View File

@@ -74,6 +74,7 @@ import { HistoryItemLabelProvider } from "../query-history/history-item-label-pr
import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../common/errors";
import { ResultsViewCommands } from "../common/commands";
import { App } from "../common/app";
/**
* results-view.ts
@@ -168,13 +169,13 @@ export class ResultsView extends AbstractWebview<
);
constructor(
public ctx: vscode.ExtensionContext,
app: App,
private databaseManager: DatabaseManager,
public cliServer: CodeQLCliServer,
public logger: Logger,
private labelProvider: HistoryItemLabelProvider,
) {
super(ctx);
super(app);
this.push(this._diagnosticCollection);
this.push(
vscode.window.onDidChangeTextEditorSelection(

View File

@@ -1,4 +1,5 @@
import { ExtensionContext, window } from "vscode";
import { window } from "vscode";
import { App } from "../../common/app";
import { DisposableObject } from "../../common/disposable-object";
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
import { Method } from "../method";
@@ -6,10 +7,10 @@ import { Method } from "../method";
export class MethodModelingPanel extends DisposableObject {
private readonly provider: MethodModelingViewProvider;
constructor(context: ExtensionContext) {
constructor(app: App) {
super();
this.provider = new MethodModelingViewProvider(context);
this.provider = new MethodModelingViewProvider(app);
this.push(
window.registerWebviewViewProvider(
MethodModelingViewProvider.viewType,

View File

@@ -1,10 +1,11 @@
import * as vscode from "vscode";
import { WebviewViewProvider } from "vscode";
import { Uri, WebviewViewProvider } from "vscode";
import { getHtmlForWebview } from "../../common/vscode/webview-html";
import { FromMethodModelingMessage } from "../../common/interface-types";
import { telemetryListener } from "../../common/vscode/telemetry";
import { showAndLogExceptionWithTelemetry } from "../../common/logging/notifications";
import { extLogger } from "../../common/logging/vscode/loggers";
import { App } from "../../common/app";
import { redactableError } from "../../common/errors";
import { Method } from "../method";
@@ -13,7 +14,7 @@ export class MethodModelingViewProvider implements WebviewViewProvider {
private webviewView: vscode.WebviewView | undefined = undefined;
constructor(private readonly context: vscode.ExtensionContext) {}
constructor(private readonly app: App) {}
/**
* This is called when a view first becomes visible. This may happen when the view is
@@ -26,11 +27,11 @@ export class MethodModelingViewProvider implements WebviewViewProvider {
) {
webviewView.webview.options = {
enableScripts: true,
localResourceRoots: [this.context.extensionUri],
localResourceRoots: [Uri.file(this.app.extensionPath)],
};
const html = getHtmlForWebview(
this.context,
this.app,
webviewView.webview,
"method-modeling",
{

View File

@@ -1,4 +1,3 @@
import { ExtensionContext } from "vscode";
import { ModelEditorView } from "./model-editor-view";
import { ModelEditorCommands } from "../common/commands";
import { CliVersionConstraint, CodeQLCliServer } from "../codeql-cli/cli";
@@ -31,7 +30,6 @@ export class ModelEditorModule extends DisposableObject {
private mostRecentlyActiveView: ModelEditorView | undefined = undefined;
private constructor(
private readonly ctx: ExtensionContext,
private readonly app: App,
private readonly databaseManager: DatabaseManager,
private readonly cliServer: CodeQLCliServer,
@@ -41,7 +39,7 @@ export class ModelEditorModule extends DisposableObject {
super();
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
this.methodsUsagePanel = this.push(new MethodsUsagePanel(cliServer));
this.methodModelingPanel = this.push(new MethodModelingPanel(ctx));
this.methodModelingPanel = this.push(new MethodModelingPanel(app));
}
private handleViewBecameActive(view: ModelEditorView): void {
@@ -59,7 +57,6 @@ export class ModelEditorModule extends DisposableObject {
}
public static async initialize(
ctx: ExtensionContext,
app: App,
databaseManager: DatabaseManager,
cliServer: CodeQLCliServer,
@@ -67,7 +64,6 @@ export class ModelEditorModule extends DisposableObject {
queryStorageDir: string,
): Promise<ModelEditorModule> {
const modelEditorModule = new ModelEditorModule(
ctx,
app,
databaseManager,
cliServer,
@@ -153,7 +149,6 @@ export class ModelEditorModule extends DisposableObject {
});
const view = new ModelEditorView(
this.ctx,
this.app,
this.databaseManager,
this.cliServer,

View File

@@ -1,10 +1,4 @@
import {
CancellationTokenSource,
ExtensionContext,
Uri,
ViewColumn,
window,
} from "vscode";
import { CancellationTokenSource, Uri, ViewColumn, window } from "vscode";
import {
AbstractWebview,
WebviewPanelConfig,
@@ -37,7 +31,6 @@ import { ExtensionPack } from "./shared/extension-pack";
import { showFlowGeneration, showLlmGeneration } from "../config";
import { Mode } from "./shared/mode";
import { loadModeledMethods, saveModeledMethods } from "./modeled-method-fs";
import { join } from "path";
import { pickExtensionPack } from "./extension-pack-picker";
import { getLanguageDisplayName } from "../common/query-language";
import { AutoModeler } from "./auto-modeler";
@@ -54,8 +47,7 @@ export class ModelEditorView extends AbstractWebview<
private hideModeledMethods: boolean;
public constructor(
ctx: ExtensionContext,
private readonly app: App,
protected readonly app: App,
private readonly databaseManager: DatabaseManager,
private readonly cliServer: CodeQLCliServer,
private readonly queryRunner: QueryRunner,
@@ -79,7 +71,7 @@ export class ModelEditorView extends AbstractWebview<
view: ModelEditorView,
) => boolean,
) {
super(ctx);
super(app);
this.autoModeler = new AutoModeler(
app,
@@ -158,11 +150,13 @@ export class ModelEditorView extends AbstractWebview<
preserveFocus: true,
view: "model-editor",
iconPath: {
dark: Uri.file(
join(this.ctx.extensionPath, "media/dark/symbol-misc.svg"),
dark: Uri.joinPath(
Uri.file(this.app.extensionPath),
"media/dark/symbol-misc.svg",
),
light: Uri.file(
join(this.ctx.extensionPath, "media/light/symbol-misc.svg"),
light: Uri.joinPath(
Uri.file(this.app.extensionPath),
"media/light/symbol-misc.svg",
),
},
};
@@ -493,7 +487,6 @@ export class ModelEditorView extends AbstractWebview<
}
const view = new ModelEditorView(
this.ctx,
this.app,
this.databaseManager,
this.cliServer,

View File

@@ -1,4 +1,4 @@
import { ExtensionContext, ViewColumn } from "vscode";
import { ViewColumn } from "vscode";
import {
AbstractWebview,
WebviewPanelConfig,
@@ -10,6 +10,7 @@ import {
ToDataFlowPathsMessage,
} from "../common/interface-types";
import { DataFlowPaths } from "./shared/data-flow-paths";
import { App } from "../common/app";
import { redactableError } from "../common/errors";
import { extLogger } from "../common/logging/vscode";
import { showAndLogExceptionWithTelemetry } from "../common/logging";
@@ -20,8 +21,8 @@ export class DataFlowPathsView extends AbstractWebview<
> {
public static readonly viewType = "codeQL.dataFlowPaths";
public constructor(ctx: ExtensionContext) {
super(ctx);
public constructor(app: App) {
super(app);
}
public async showDataFlows(dataFlowPaths: DataFlowPaths) {

View File

@@ -10,7 +10,6 @@ import {
CancellationToken,
env,
EventEmitter,
ExtensionContext,
Uri,
ViewColumn,
window as Window,
@@ -116,7 +115,6 @@ export class VariantAnalysisManager
>();
constructor(
private readonly ctx: ExtensionContext,
private readonly app: App,
private readonly cliServer: CodeQLCliServer,
private readonly storagePath: string,
@@ -347,9 +345,7 @@ export class VariantAnalysisManager
}
if (!this.views.has(variantAnalysisId)) {
// The view will register itself with the manager, so we don't need to do anything here.
this.track(
new VariantAnalysisView(this.ctx, this.app, variantAnalysisId, this),
);
this.track(new VariantAnalysisView(this.app, variantAnalysisId, this));
}
const variantAnalysisView = this.views.get(variantAnalysisId)!;

View File

@@ -1,4 +1,4 @@
import { ExtensionContext, WebviewPanel, WebviewPanelSerializer } from "vscode";
import { WebviewPanel, WebviewPanelSerializer } from "vscode";
import { VariantAnalysisView } from "./variant-analysis-view";
import { VariantAnalysisState } from "../common/interface-types";
import { VariantAnalysisViewManager } from "./variant-analysis-view-manager";
@@ -11,10 +11,7 @@ export class VariantAnalysisViewSerializer implements WebviewPanelSerializer {
private manager?: VariantAnalysisViewManager<VariantAnalysisView>;
public constructor(
private readonly ctx: ExtensionContext,
private readonly app: App,
) {}
public constructor(private readonly app: App) {}
onExtensionLoaded(
manager: VariantAnalysisViewManager<VariantAnalysisView>,
@@ -65,7 +62,6 @@ export class VariantAnalysisViewSerializer implements WebviewPanelSerializer {
}
const view = new VariantAnalysisView(
this.ctx,
this.app,
variantAnalysisState.variantAnalysisId,
manager,

View File

@@ -1,4 +1,4 @@
import { ExtensionContext, ViewColumn } from "vscode";
import { ViewColumn } from "vscode";
import {
AbstractWebview,
WebviewPanelConfig,
@@ -39,16 +39,15 @@ export class VariantAnalysisView
private readonly dataFlowPathsView: DataFlowPathsView;
public constructor(
ctx: ExtensionContext,
private readonly app: App,
protected readonly app: App,
public readonly variantAnalysisId: number,
private readonly manager: VariantAnalysisViewManager<VariantAnalysisView>,
) {
super(ctx);
super(app);
manager.registerView(this);
this.dataFlowPathsView = new DataFlowPathsView(ctx);
this.dataFlowPathsView = new DataFlowPathsView(app);
}
public async openView() {

View File

@@ -76,7 +76,6 @@ describe("Variant Analysis Manager", () => {
extLogger,
);
variantAnalysisManager = new VariantAnalysisManager(
extension.ctx,
app,
cli,
storagePath,

View File

@@ -51,7 +51,6 @@ describe("Variant Analysis Manager", () => {
extLogger,
);
variantAnalysisManager = new VariantAnalysisManager(
extension.ctx,
app,
cli,
storagePath,