Add ability to set method for modeling in the modeling panel (#2767)

This commit is contained in:
Charis Kyriakou
2023-09-01 12:16:10 +01:00
committed by GitHub
parent b5d6c4d84c
commit ac7a37c02e
6 changed files with 73 additions and 26 deletions

View File

@@ -593,3 +593,10 @@ export type FromModelEditorMessage =
export type FromMethodModelingMessage =
| TelemetryMessage
| UnhandledErrorMessage;
interface SetMethodMessage {
t: "setMethod";
method: ExternalApiUsage;
}
export type ToMethodModelingMessage = SetMethodMessage;

View File

@@ -1,17 +1,24 @@
import { ExtensionContext, window } from "vscode";
import { DisposableObject } from "../../common/disposable-object";
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
import { ExternalApiUsage } from "../external-api-usage";
export class MethodModelingPanel extends DisposableObject {
private readonly provider: MethodModelingViewProvider;
constructor(context: ExtensionContext) {
super();
const provider = new MethodModelingViewProvider(context);
this.provider = new MethodModelingViewProvider(context);
this.push(
window.registerWebviewViewProvider(
MethodModelingViewProvider.viewType,
provider,
this.provider,
),
);
}
public async setMethod(method: ExternalApiUsage): Promise<void> {
await this.provider.setMethod(method);
}
}

View File

@@ -6,10 +6,13 @@ import { telemetryListener } from "../../common/vscode/telemetry";
import { showAndLogExceptionWithTelemetry } from "../../common/logging/notifications";
import { extLogger } from "../../common/logging/vscode/loggers";
import { redactableError } from "../../common/errors";
import { ExternalApiUsage } from "../external-api-usage";
export class MethodModelingViewProvider implements WebviewViewProvider {
public static readonly viewType = "codeQLMethodModeling";
private webviewView: vscode.WebviewView | undefined = undefined;
constructor(private readonly context: vscode.ExtensionContext) {}
/**
@@ -39,6 +42,17 @@ export class MethodModelingViewProvider implements WebviewViewProvider {
webviewView.webview.html = html;
webviewView.webview.onDidReceiveMessage(async (msg) => this.onMessage(msg));
this.webviewView = webviewView;
}
public async setMethod(method: ExternalApiUsage): Promise<void> {
if (this.webviewView) {
await this.webviewView.webview.postMessage({
t: "setMethod",
method,
});
}
}
private async onMessage(msg: FromMethodModelingMessage): Promise<void> {

View File

@@ -17,7 +17,7 @@ import { DisposableObject } from "../common/disposable-object";
import { MethodsUsagePanel } from "./methods-usage/methods-usage-panel";
import { Mode } from "./shared/mode";
import { showResolvableLocation } from "../databases/local-databases/locations";
import { Usage } from "./external-api-usage";
import { ExternalApiUsage, Usage } from "./external-api-usage";
import { setUpPack } from "./model-editor-queries";
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
@@ -26,6 +26,7 @@ const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
export class ModelEditorModule extends DisposableObject {
private readonly queryStorageDir: string;
private readonly methodsUsagePanel: MethodsUsagePanel;
private readonly methodModelingPanel: MethodModelingPanel;
private mostRecentlyActiveView: ModelEditorView | undefined = undefined;
@@ -40,7 +41,7 @@ export class ModelEditorModule extends DisposableObject {
super();
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
this.methodsUsagePanel = this.push(new MethodsUsagePanel(cliServer));
this.push(new MethodModelingPanel(ctx));
this.methodModelingPanel = this.push(new MethodModelingPanel(ctx));
}
private handleViewBecameActive(view: ModelEditorView): void {
@@ -149,7 +150,7 @@ export class ModelEditorModule extends DisposableObject {
modelFile,
Mode.Application,
this.methodsUsagePanel.setState.bind(this.methodsUsagePanel),
this.methodsUsagePanel.revealItem.bind(this.methodsUsagePanel),
this.showMethod.bind(this),
this.handleViewBecameActive.bind(this),
this.handleViewWasDisposed.bind(this),
this.isMostRecentlyActiveView.bind(this),
@@ -173,4 +174,24 @@ export class ModelEditorModule extends DisposableObject {
private async initialize(): Promise<void> {
await ensureDir(this.queryStorageDir);
}
private async showMethod(usage: Usage): Promise<void> {
await this.methodsUsagePanel.revealItem(usage);
// For now, just construct a dummy method and show it in the method modeling panel
// because the method isn't easily accessible yet.
const method: ExternalApiUsage = {
library: "sql2o",
libraryVersion: "1.6.0",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
supported: true,
supportedType: "summary",
usages: [],
};
await this.methodModelingPanel.setMethod(method);
}
}

View File

@@ -65,7 +65,7 @@ export class ModelEditorView extends AbstractWebview<
databaseItem: DatabaseItem,
hideModeledApis: boolean,
) => Promise<void>,
private readonly revealItemInUsagePanel: (usage: Usage) => Promise<void>,
private readonly showMethod: (usage: Usage) => Promise<void>,
private readonly handleViewBecameActive: (view: ModelEditorView) => void,
private readonly handleViewWasDisposed: (view: ModelEditorView) => void,
private readonly isMostRecentlyActiveView: (
@@ -268,7 +268,7 @@ export class ModelEditorView extends AbstractWebview<
}
protected async handleJumpToUsage(usage: Usage) {
await this.revealItemInUsagePanel(usage);
await this.showMethod(usage);
await showResolvableLocation(usage.url, this.databaseItem, this.app.logger);
}
@@ -439,7 +439,7 @@ export class ModelEditorView extends AbstractWebview<
modelFile,
Mode.Framework,
this.updateMethodsUsagePanelState,
this.revealItemInUsagePanel,
this.showMethod,
this.handleViewBecameActive,
this.handleViewWasDisposed,
this.isMostRecentlyActiveView,

View File

@@ -1,14 +1,23 @@
import * as React from "react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { MethodModeling } from "./MethodModeling";
import { ModelingStatus } from "../model-editor/ModelingStatusIndicator";
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
import { ToMethodModelingMessage } from "../../common/interface-types";
import { assertNever } from "../../common/helpers-pure";
export function MethodModelingView(): JSX.Element {
const [method, setMethod] = useState<ExternalApiUsage | undefined>(undefined);
useEffect(() => {
const listener = (evt: MessageEvent) => {
if (evt.origin === window.origin) {
// Nothing to do yet.
const msg: ToMethodModelingMessage = evt.data;
if (msg.t === "setMethod") {
setMethod(msg.method);
} else {
assertNever(msg.t);
}
} else {
// sanitize origin
const origin = evt.origin.replace(/\n|\r/g, "");
@@ -22,23 +31,12 @@ export function MethodModelingView(): JSX.Element {
};
}, []);
if (!method) {
return <>Select method to model</>;
}
const modelingStatus: ModelingStatus = "saved";
const externalApiUsage: ExternalApiUsage = {
library: "sql2o",
libraryVersion: "1.6.0",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
supported: true,
supportedType: "summary",
usages: [],
};
return (
<MethodModeling
modelingStatus={modelingStatus}
externalApiUsage={externalApiUsage}
/>
<MethodModeling modelingStatus={modelingStatus} externalApiUsage={method} />
);
}