Extract base functionality for WebviewViewProviders into an abstract class (#2895)
This commit is contained in:
@@ -598,8 +598,7 @@ export type FromModelEditorMessage =
|
||||
| SetModeledMethodMessage;
|
||||
|
||||
export type FromMethodModelingMessage =
|
||||
| TelemetryMessage
|
||||
| UnhandledErrorMessage
|
||||
| CommonFromViewMessages
|
||||
| SetModeledMethodMessage;
|
||||
|
||||
interface SetMethodMessage {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import * as vscode from "vscode";
|
||||
import { Uri, WebviewViewProvider } from "vscode";
|
||||
import { WebviewKind, WebviewMessage, getHtmlForWebview } from "./webview-html";
|
||||
import { Disposable } from "../disposable-object";
|
||||
import { App } from "../app";
|
||||
|
||||
export abstract class AbstractWebviewViewProvider<
|
||||
ToMessage extends WebviewMessage,
|
||||
FromMessage extends WebviewMessage,
|
||||
> implements WebviewViewProvider
|
||||
{
|
||||
protected webviewView: vscode.WebviewView | undefined = undefined;
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly app: App,
|
||||
private readonly webviewKind: WebviewKind,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* This is called when a view first becomes visible. This may happen when the view is
|
||||
* first loaded or when the user hides and then shows a view again.
|
||||
*/
|
||||
public resolveWebviewView(
|
||||
webviewView: vscode.WebviewView,
|
||||
_context: vscode.WebviewViewResolveContext,
|
||||
_token: vscode.CancellationToken,
|
||||
) {
|
||||
webviewView.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [Uri.file(this.app.extensionPath)],
|
||||
};
|
||||
|
||||
const html = getHtmlForWebview(
|
||||
this.app,
|
||||
webviewView.webview,
|
||||
this.webviewKind,
|
||||
{
|
||||
allowInlineStyles: true,
|
||||
allowWasmEval: false,
|
||||
},
|
||||
);
|
||||
|
||||
webviewView.webview.html = html;
|
||||
|
||||
this.webviewView = webviewView;
|
||||
|
||||
webviewView.webview.onDidReceiveMessage(async (msg) => this.onMessage(msg));
|
||||
webviewView.onDidDispose(() => this.dispose());
|
||||
}
|
||||
|
||||
protected get isShowingView() {
|
||||
return this.webviewView?.visible ?? false;
|
||||
}
|
||||
|
||||
protected async postMessage(msg: ToMessage): Promise<void> {
|
||||
await this.webviewView?.webview.postMessage(msg);
|
||||
}
|
||||
|
||||
protected dispose() {
|
||||
while (this.disposables.length > 0) {
|
||||
const disposable = this.disposables.pop()!;
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
this.webviewView = undefined;
|
||||
}
|
||||
|
||||
protected push<T extends Disposable>(obj: T): T {
|
||||
if (obj !== undefined) {
|
||||
this.disposables.push(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected abstract onMessage(msg: FromMessage): Promise<void>;
|
||||
|
||||
/**
|
||||
* This is called when a view first becomes visible. This may happen when the view is
|
||||
* first loaded or when the user hides and then shows a view again.
|
||||
*/
|
||||
protected onWebViewLoaded(): void {
|
||||
// Do nothing by default.
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ export class MethodModelingPanel extends DisposableObject {
|
||||
super();
|
||||
|
||||
this.provider = new MethodModelingViewProvider(app, modelingStore);
|
||||
this.push(this.provider);
|
||||
this.push(
|
||||
window.registerWebviewViewProvider(
|
||||
MethodModelingViewProvider.viewType,
|
||||
|
||||
@@ -1,82 +1,51 @@
|
||||
import * as vscode from "vscode";
|
||||
import { Uri, WebviewViewProvider } from "vscode";
|
||||
import { getHtmlForWebview } from "../../common/vscode/webview-html";
|
||||
import { FromMethodModelingMessage } from "../../common/interface-types";
|
||||
import {
|
||||
FromMethodModelingMessage,
|
||||
ToMethodModelingMessage,
|
||||
} 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";
|
||||
import { DisposableObject } from "../../common/disposable-object";
|
||||
import { ModelingStore } from "../modeling-store";
|
||||
import { AbstractWebviewViewProvider } from "../../common/vscode/abstract-webview-view-provider";
|
||||
|
||||
export class MethodModelingViewProvider
|
||||
extends DisposableObject
|
||||
implements WebviewViewProvider
|
||||
{
|
||||
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
|
||||
ToMethodModelingMessage,
|
||||
FromMethodModelingMessage
|
||||
> {
|
||||
public static readonly viewType = "codeQLMethodModeling";
|
||||
|
||||
private webviewView: vscode.WebviewView | undefined = undefined;
|
||||
|
||||
private method: Method | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
private readonly app: App,
|
||||
app: App,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
) {
|
||||
super();
|
||||
super(app, "method-modeling");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a view first becomes visible. This may happen when the view is
|
||||
* first loaded or when the user hides and then shows a view again.
|
||||
*/
|
||||
public resolveWebviewView(
|
||||
webviewView: vscode.WebviewView,
|
||||
_context: vscode.WebviewViewResolveContext,
|
||||
_token: vscode.CancellationToken,
|
||||
) {
|
||||
webviewView.webview.options = {
|
||||
enableScripts: true,
|
||||
localResourceRoots: [Uri.file(this.app.extensionPath)],
|
||||
};
|
||||
|
||||
const html = getHtmlForWebview(
|
||||
this.app,
|
||||
webviewView.webview,
|
||||
"method-modeling",
|
||||
{
|
||||
allowInlineStyles: true,
|
||||
allowWasmEval: false,
|
||||
},
|
||||
);
|
||||
|
||||
webviewView.webview.html = html;
|
||||
|
||||
webviewView.webview.onDidReceiveMessage(async (msg) => this.onMessage(msg));
|
||||
|
||||
this.webviewView = webviewView;
|
||||
|
||||
this.setInitialState(webviewView);
|
||||
protected override onWebViewLoaded(): void {
|
||||
this.setInitialState();
|
||||
this.registerToModelingStoreEvents();
|
||||
}
|
||||
|
||||
public async setMethod(method: Method): Promise<void> {
|
||||
this.method = method;
|
||||
|
||||
if (this.webviewView) {
|
||||
await this.webviewView.webview.postMessage({
|
||||
if (this.isShowingView) {
|
||||
await this.postMessage({
|
||||
t: "setMethod",
|
||||
method,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private setInitialState(webviewView: vscode.WebviewView): void {
|
||||
private setInitialState(): void {
|
||||
const selectedMethod = this.modelingStore.getSelectedMethodDetails();
|
||||
if (selectedMethod) {
|
||||
void webviewView.webview.postMessage({
|
||||
void this.postMessage({
|
||||
t: "setSelectedMethod",
|
||||
method: selectedMethod.method,
|
||||
modeledMethod: selectedMethod.modeledMethod,
|
||||
@@ -85,8 +54,28 @@ export class MethodModelingViewProvider
|
||||
}
|
||||
}
|
||||
|
||||
private async onMessage(msg: FromMethodModelingMessage): Promise<void> {
|
||||
protected override async onMessage(
|
||||
msg: FromMethodModelingMessage,
|
||||
): Promise<void> {
|
||||
switch (msg.t) {
|
||||
case "viewLoaded":
|
||||
this.onWebViewLoaded();
|
||||
break;
|
||||
|
||||
case "telemetry":
|
||||
telemetryListener?.sendUIInteraction(msg.action);
|
||||
break;
|
||||
|
||||
case "unhandledError":
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
extLogger,
|
||||
telemetryListener,
|
||||
redactableError(
|
||||
msg.error,
|
||||
)`Unhandled error in method modeling view: ${msg.error.message}`,
|
||||
);
|
||||
break;
|
||||
|
||||
case "setModeledMethod": {
|
||||
const activeState = this.modelingStore.getStateForActiveDb();
|
||||
if (!activeState) {
|
||||
@@ -98,20 +87,6 @@ export class MethodModelingViewProvider
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "telemetry": {
|
||||
telemetryListener?.sendUIInteraction(msg.action);
|
||||
break;
|
||||
}
|
||||
case "unhandledError":
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
extLogger,
|
||||
telemetryListener,
|
||||
redactableError(
|
||||
msg.error,
|
||||
)`Unhandled error in method modeling view: ${msg.error.message}`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user