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 = export type FromMethodModelingMessage =
| TelemetryMessage | TelemetryMessage
| UnhandledErrorMessage; | UnhandledErrorMessage;
interface SetMethodMessage {
t: "setMethod";
method: ExternalApiUsage;
}
export type ToMethodModelingMessage = SetMethodMessage;

View File

@@ -1,17 +1,24 @@
import { ExtensionContext, window } from "vscode"; import { ExtensionContext, window } from "vscode";
import { DisposableObject } from "../../common/disposable-object"; import { DisposableObject } from "../../common/disposable-object";
import { MethodModelingViewProvider } from "./method-modeling-view-provider"; import { MethodModelingViewProvider } from "./method-modeling-view-provider";
import { ExternalApiUsage } from "../external-api-usage";
export class MethodModelingPanel extends DisposableObject { export class MethodModelingPanel extends DisposableObject {
private readonly provider: MethodModelingViewProvider;
constructor(context: ExtensionContext) { constructor(context: ExtensionContext) {
super(); super();
const provider = new MethodModelingViewProvider(context); this.provider = new MethodModelingViewProvider(context);
this.push( this.push(
window.registerWebviewViewProvider( window.registerWebviewViewProvider(
MethodModelingViewProvider.viewType, 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 { showAndLogExceptionWithTelemetry } from "../../common/logging/notifications";
import { extLogger } from "../../common/logging/vscode/loggers"; import { extLogger } from "../../common/logging/vscode/loggers";
import { redactableError } from "../../common/errors"; import { redactableError } from "../../common/errors";
import { ExternalApiUsage } from "../external-api-usage";
export class MethodModelingViewProvider implements WebviewViewProvider { export class MethodModelingViewProvider implements WebviewViewProvider {
public static readonly viewType = "codeQLMethodModeling"; public static readonly viewType = "codeQLMethodModeling";
private webviewView: vscode.WebviewView | undefined = undefined;
constructor(private readonly context: vscode.ExtensionContext) {} constructor(private readonly context: vscode.ExtensionContext) {}
/** /**
@@ -39,6 +42,17 @@ export class MethodModelingViewProvider implements WebviewViewProvider {
webviewView.webview.html = html; webviewView.webview.html = html;
webviewView.webview.onDidReceiveMessage(async (msg) => this.onMessage(msg)); 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> { 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 { MethodsUsagePanel } from "./methods-usage/methods-usage-panel";
import { Mode } from "./shared/mode"; import { Mode } from "./shared/mode";
import { showResolvableLocation } from "../databases/local-databases/locations"; 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 { setUpPack } from "./model-editor-queries";
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel"; import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
@@ -26,6 +26,7 @@ const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
export class ModelEditorModule extends DisposableObject { export class ModelEditorModule extends DisposableObject {
private readonly queryStorageDir: string; private readonly queryStorageDir: string;
private readonly methodsUsagePanel: MethodsUsagePanel; private readonly methodsUsagePanel: MethodsUsagePanel;
private readonly methodModelingPanel: MethodModelingPanel;
private mostRecentlyActiveView: ModelEditorView | undefined = undefined; private mostRecentlyActiveView: ModelEditorView | undefined = undefined;
@@ -40,7 +41,7 @@ export class ModelEditorModule extends DisposableObject {
super(); super();
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results"); this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
this.methodsUsagePanel = this.push(new MethodsUsagePanel(cliServer)); this.methodsUsagePanel = this.push(new MethodsUsagePanel(cliServer));
this.push(new MethodModelingPanel(ctx)); this.methodModelingPanel = this.push(new MethodModelingPanel(ctx));
} }
private handleViewBecameActive(view: ModelEditorView): void { private handleViewBecameActive(view: ModelEditorView): void {
@@ -149,7 +150,7 @@ export class ModelEditorModule extends DisposableObject {
modelFile, modelFile,
Mode.Application, Mode.Application,
this.methodsUsagePanel.setState.bind(this.methodsUsagePanel), this.methodsUsagePanel.setState.bind(this.methodsUsagePanel),
this.methodsUsagePanel.revealItem.bind(this.methodsUsagePanel), this.showMethod.bind(this),
this.handleViewBecameActive.bind(this), this.handleViewBecameActive.bind(this),
this.handleViewWasDisposed.bind(this), this.handleViewWasDisposed.bind(this),
this.isMostRecentlyActiveView.bind(this), this.isMostRecentlyActiveView.bind(this),
@@ -173,4 +174,24 @@ export class ModelEditorModule extends DisposableObject {
private async initialize(): Promise<void> { private async initialize(): Promise<void> {
await ensureDir(this.queryStorageDir); 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, databaseItem: DatabaseItem,
hideModeledApis: boolean, hideModeledApis: boolean,
) => Promise<void>, ) => Promise<void>,
private readonly revealItemInUsagePanel: (usage: Usage) => Promise<void>, private readonly showMethod: (usage: Usage) => Promise<void>,
private readonly handleViewBecameActive: (view: ModelEditorView) => void, private readonly handleViewBecameActive: (view: ModelEditorView) => void,
private readonly handleViewWasDisposed: (view: ModelEditorView) => void, private readonly handleViewWasDisposed: (view: ModelEditorView) => void,
private readonly isMostRecentlyActiveView: ( private readonly isMostRecentlyActiveView: (
@@ -268,7 +268,7 @@ export class ModelEditorView extends AbstractWebview<
} }
protected async handleJumpToUsage(usage: Usage) { protected async handleJumpToUsage(usage: Usage) {
await this.revealItemInUsagePanel(usage); await this.showMethod(usage);
await showResolvableLocation(usage.url, this.databaseItem, this.app.logger); await showResolvableLocation(usage.url, this.databaseItem, this.app.logger);
} }
@@ -439,7 +439,7 @@ export class ModelEditorView extends AbstractWebview<
modelFile, modelFile,
Mode.Framework, Mode.Framework,
this.updateMethodsUsagePanelState, this.updateMethodsUsagePanelState,
this.revealItemInUsagePanel, this.showMethod,
this.handleViewBecameActive, this.handleViewBecameActive,
this.handleViewWasDisposed, this.handleViewWasDisposed,
this.isMostRecentlyActiveView, this.isMostRecentlyActiveView,

View File

@@ -1,14 +1,23 @@
import * as React from "react"; import * as React from "react";
import { useEffect } from "react"; import { useEffect, useState } from "react";
import { MethodModeling } from "./MethodModeling"; import { MethodModeling } from "./MethodModeling";
import { ModelingStatus } from "../model-editor/ModelingStatusIndicator"; import { ModelingStatus } from "../model-editor/ModelingStatusIndicator";
import { ExternalApiUsage } from "../../model-editor/external-api-usage"; 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 { export function MethodModelingView(): JSX.Element {
const [method, setMethod] = useState<ExternalApiUsage | undefined>(undefined);
useEffect(() => { useEffect(() => {
const listener = (evt: MessageEvent) => { const listener = (evt: MessageEvent) => {
if (evt.origin === window.origin) { 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 { } else {
// sanitize origin // sanitize origin
const origin = evt.origin.replace(/\n|\r/g, ""); 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 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 ( return (
<MethodModeling <MethodModeling modelingStatus={modelingStatus} externalApiUsage={method} />
modelingStatus={modelingStatus}
externalApiUsage={externalApiUsage}
/>
); );
} }