Skip to content

Commit cffecaf

Browse files
authored
Add a new "model alerts" webview (for showing results from model evaluation) (#3436)
1 parent 6f1504a commit cffecaf

10 files changed

Lines changed: 136 additions & 9 deletions

File tree

extensions/ql-vscode/src/common/interface-types.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,10 @@ interface StopModelEvaluationMessage {
600600
t: "stopModelEvaluation";
601601
}
602602

603+
interface OpenModelAlertsViewMessage {
604+
t: "openModelAlertsView";
605+
}
606+
603607
interface ModelDependencyMessage {
604608
t: "modelDependency";
605609
}
@@ -671,7 +675,8 @@ export type FromModelEditorMessage =
671675
| HideModeledMethodsMessage
672676
| SetMultipleModeledMethodsMessage
673677
| StartModelEvaluationMessage
674-
| StopModelEvaluationMessage;
678+
| StopModelEvaluationMessage
679+
| OpenModelAlertsViewMessage;
675680

676681
interface RevealInEditorMessage {
677682
t: "revealInModelEditor";
@@ -721,3 +726,11 @@ export type ToMethodModelingMessage =
721726
| SetInModelingModeMessage
722727
| SetInProgressMessage
723728
| SetProcessedByAutoModelMessage;
729+
730+
interface SetModelAlertsMessage {
731+
t: "setModelAlerts";
732+
}
733+
734+
export type ToModelAlertsMessage = SetModelAlertsMessage;
735+
736+
export type FromModelAlertsMessage = CommonFromViewMessages;

extensions/ql-vscode/src/common/vscode/webview-html.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export type WebviewKind =
1010
| "variant-analysis"
1111
| "data-flow-paths"
1212
| "model-editor"
13-
| "method-modeling";
13+
| "method-modeling"
14+
| "model-alerts";
1415

1516
export interface WebviewMessage {
1617
t: string;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { ViewColumn } from "vscode";
2+
import type { WebviewPanelConfig } from "../../common/vscode/abstract-webview";
3+
import { AbstractWebview } from "../../common/vscode/abstract-webview";
4+
import { assertNever } from "../../common/helpers-pure";
5+
import { telemetryListener } from "../../common/vscode/telemetry";
6+
import type {
7+
FromModelAlertsMessage,
8+
ToModelAlertsMessage,
9+
} from "../../common/interface-types";
10+
import type { App } from "../../common/app";
11+
import { redactableError } from "../../common/errors";
12+
import { extLogger } from "../../common/logging/vscode";
13+
import { showAndLogExceptionWithTelemetry } from "../../common/logging";
14+
15+
export class ModelAlertsView extends AbstractWebview<
16+
ToModelAlertsMessage,
17+
FromModelAlertsMessage
18+
> {
19+
public static readonly viewType = "codeQL.modelAlerts";
20+
21+
public constructor(app: App) {
22+
super(app);
23+
}
24+
25+
public async showView() {
26+
const panel = await this.getPanel();
27+
panel.reveal(undefined, true);
28+
29+
await this.waitForPanelLoaded();
30+
}
31+
32+
protected async getPanelConfig(): Promise<WebviewPanelConfig> {
33+
return {
34+
viewId: ModelAlertsView.viewType,
35+
title: "Model Alerts",
36+
viewColumn: ViewColumn.Active,
37+
preserveFocus: true,
38+
view: "model-alerts",
39+
};
40+
}
41+
42+
protected onPanelDispose(): void {
43+
// Nothing to dispose
44+
}
45+
46+
protected async onMessage(msg: FromModelAlertsMessage): Promise<void> {
47+
switch (msg.t) {
48+
case "viewLoaded":
49+
this.onWebViewLoaded();
50+
break;
51+
case "telemetry":
52+
telemetryListener?.sendUIInteraction(msg.action);
53+
break;
54+
case "unhandledError":
55+
void showAndLogExceptionWithTelemetry(
56+
extLogger,
57+
telemetryListener,
58+
redactableError(
59+
msg.error,
60+
)`Unhandled error in model alerts view: ${msg.error.message}`,
61+
);
62+
break;
63+
default:
64+
assertNever(msg);
65+
}
66+
}
67+
}

extensions/ql-vscode/src/model-editor/model-editor-view.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class ModelEditorView extends AbstractWebview<
125125
this.languageDefinition = getModelsAsDataLanguage(language);
126126

127127
this.modelEvaluator = new ModelEvaluator(
128-
this.app.logger,
128+
this.app,
129129
this.cliServer,
130130
modelingStore,
131131
modelingEvents,
@@ -380,6 +380,9 @@ export class ModelEditorView extends AbstractWebview<
380380
case "stopModelEvaluation":
381381
await this.modelEvaluator.stopEvaluation();
382382
break;
383+
case "openModelAlertsView":
384+
await this.modelEvaluator.openModelAlertsView();
385+
break;
383386
case "telemetry":
384387
telemetryListener?.sendUIInteraction(msg.action);
385388
break;

extensions/ql-vscode/src/model-editor/model-evaluator.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type { DatabaseItem } from "../databases/local-databases";
44
import type { ModelEvaluationRun } from "./model-evaluation-run";
55
import { DisposableObject } from "../common/disposable-object";
66
import type { ModelEvaluationRunState } from "./shared/model-evaluation-run-state";
7-
import type { BaseLogger } from "../common/logging";
87
import type { CodeQLCliServer } from "../codeql-cli/cli";
98
import type { VariantAnalysisManager } from "../variant-analysis/variant-analysis-manager";
109
import type { QueryLanguage } from "../common/query-language";
@@ -18,6 +17,8 @@ import type { VariantAnalysis } from "../variant-analysis/shared/variant-analysi
1817
import type { CancellationToken } from "vscode";
1918
import { CancellationTokenSource } from "vscode";
2019
import type { QlPackDetails } from "../variant-analysis/ql-pack-details";
20+
import type { App } from "../common/app";
21+
import { ModelAlertsView } from "./model-alerts/model-alerts-view";
2122

2223
export class ModelEvaluator extends DisposableObject {
2324
// Cancellation token source to allow cancelling of the current run
@@ -26,7 +27,7 @@ export class ModelEvaluator extends DisposableObject {
2627
private cancellationSource: CancellationTokenSource;
2728

2829
public constructor(
29-
private readonly logger: BaseLogger,
30+
private readonly app: App,
3031
private readonly cliServer: CodeQLCliServer,
3132
private readonly modelingStore: ModelingStore,
3233
private readonly modelingEvents: ModelingEvents,
@@ -54,7 +55,7 @@ export class ModelEvaluator extends DisposableObject {
5455

5556
// Build pack
5657
const qlPack = await resolveCodeScanningQueryPack(
57-
this.logger,
58+
this.app.logger,
5859
this.cliServer,
5960
this.language,
6061
);
@@ -82,7 +83,7 @@ export class ModelEvaluator extends DisposableObject {
8283
public async stopEvaluation() {
8384
const evaluationRun = this.modelingStore.getModelEvaluationRun(this.dbItem);
8485
if (!evaluationRun) {
85-
void this.logger.log("No active evaluation run to stop");
86+
void this.app.logger.log("No active evaluation run to stop");
8687
return;
8788
}
8889

@@ -105,6 +106,11 @@ export class ModelEvaluator extends DisposableObject {
105106
}
106107
}
107108

109+
public async openModelAlertsView() {
110+
const view = new ModelAlertsView(this.app);
111+
await view.showView();
112+
}
113+
108114
private registerToModelingEvents() {
109115
this.push(
110116
this.modelingEvents.onModelEvaluationRunChanged(async (event) => {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useEffect } from "react";
2+
3+
export function ModelAlerts(): React.JSX.Element {
4+
useEffect(() => {
5+
const listener = (evt: MessageEvent) => {
6+
if (evt.origin === window.origin) {
7+
// TODO: handle messages
8+
} else {
9+
// sanitize origin
10+
const origin = evt.origin.replace(/\n|\r/g, "");
11+
console.error(`Invalid event origin ${origin}`);
12+
}
13+
};
14+
window.addEventListener("message", listener);
15+
16+
return () => {
17+
window.removeEventListener("message", listener);
18+
};
19+
}, []);
20+
21+
return <>hello world</>;
22+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { WebviewDefinition } from "../webview-definition";
2+
import { ModelAlerts } from "./ModelAlerts";
3+
4+
const definition: WebviewDefinition = {
5+
component: <ModelAlerts />,
6+
};
7+
8+
export default definition;

extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,9 @@ export function ModelEditor({
277277
}, []);
278278

279279
const openModelAlertsView = useCallback(() => {
280-
// TODO
280+
vscode.postMessage({
281+
t: "openModelAlertsView",
282+
});
281283
}, []);
282284

283285
const onGenerateFromSourceClick = useCallback(() => {

extensions/ql-vscode/src/view/webview.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import methodModelingView from "./method-modeling";
1111
import modelEditorView from "./model-editor";
1212
import resultsView from "./results";
1313
import variantAnalysisView from "./variant-analysis";
14+
import modelAlertsView from "./model-alerts";
1415

1516
// Allow all views to use Codicons
1617
import "@vscode/codicons/dist/codicon.css";
@@ -22,6 +23,7 @@ const views: Record<string, WebviewDefinition> = {
2223
"model-editor": modelEditorView,
2324
results: resultsView,
2425
"variant-analysis": variantAnalysisView,
26+
"model-alerts": modelAlertsView,
2527
};
2628

2729
const render = () => {

extensions/ql-vscode/test/vscode-tests/activated-extension/model-editor/model-evaluator.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
2+
import type { App } from "../../../../src/common/app";
23
import type { BaseLogger } from "../../../../src/common/logging";
34
import { QueryLanguage } from "../../../../src/common/query-language";
45
import type { DatabaseItem } from "../../../../src/databases/local-databases";
@@ -15,6 +16,7 @@ import { mockedObject } from "../../../mocked-object";
1516
describe("Model Evaluator", () => {
1617
let modelEvaluator: ModelEvaluator;
1718
let logger: BaseLogger;
19+
let app: App;
1820
let cliServer: CodeQLCliServer;
1921
let modelingStore: ModelingStore;
2022
let modelingEvents: ModelingEvents;
@@ -26,6 +28,7 @@ describe("Model Evaluator", () => {
2628

2729
beforeEach(() => {
2830
logger = createMockLogger();
31+
app = mockedObject<App>({ logger });
2932
cliServer = mockedObject<CodeQLCliServer>({});
3033
getModelEvaluationRunMock = jest.fn();
3134
modelingStore = createMockModelingStore({
@@ -40,7 +43,7 @@ describe("Model Evaluator", () => {
4043
updateView = jest.fn();
4144

4245
modelEvaluator = new ModelEvaluator(
43-
logger,
46+
app,
4447
cliServer,
4548
modelingStore,
4649
modelingEvents,

0 commit comments

Comments
 (0)