From 2d1c2349f869ef05cf26632e0ba3024b6f59bf38 Mon Sep 17 00:00:00 2001 From: Charis Kyriakou Date: Mon, 18 Mar 2024 15:41:33 +0000 Subject: [PATCH] Add 'stop evaluation' action to Model Alerts view (#3487) --- .../ql-vscode/src/common/interface-types.ts | 7 ++- .../model-alerts/model-alerts-view.ts | 17 ++++++ .../src/model-editor/model-evaluator.ts | 4 ++ .../model-alerts/ModelAlerts.stories.tsx | 2 +- .../ModelAlertsHeader.stories.tsx | 52 +++++++++++++++++++ .../src/view/model-alerts/ModelAlerts.tsx | 7 +++ .../view/model-alerts/ModelAlertsActions.tsx | 39 ++++++++++++++ .../view/model-alerts/ModelAlertsHeader.tsx | 34 ++++++++++-- .../src/view/model-alerts/ModelPacks.tsx | 8 ++- .../shared/variant-analysis.ts | 4 ++ 10 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 extensions/ql-vscode/src/stories/model-alerts/ModelAlertsHeader.stories.tsx create mode 100644 extensions/ql-vscode/src/view/model-alerts/ModelAlertsActions.tsx diff --git a/extensions/ql-vscode/src/common/interface-types.ts b/extensions/ql-vscode/src/common/interface-types.ts index 4ce4653f6..87e7e785e 100644 --- a/extensions/ql-vscode/src/common/interface-types.ts +++ b/extensions/ql-vscode/src/common/interface-types.ts @@ -737,6 +737,10 @@ interface OpenModelPackMessage { path: string; } +interface StopEvaluationRunMessage { + t: "stopEvaluationRun"; +} + export type ToModelAlertsMessage = | SetModelAlertsViewStateMessage | SetVariantAnalysisMessage @@ -745,4 +749,5 @@ export type ToModelAlertsMessage = export type FromModelAlertsMessage = | CommonFromViewMessages - | OpenModelPackMessage; + | OpenModelPackMessage + | StopEvaluationRunMessage; diff --git a/extensions/ql-vscode/src/model-editor/model-alerts/model-alerts-view.ts b/extensions/ql-vscode/src/model-editor/model-alerts/model-alerts-view.ts index e7b8f41f1..57e5c7dec 100644 --- a/extensions/ql-vscode/src/model-editor/model-alerts/model-alerts-view.ts +++ b/extensions/ql-vscode/src/model-editor/model-alerts/model-alerts-view.ts @@ -20,6 +20,7 @@ import type { VariantAnalysisScannedRepositoryResult, VariantAnalysisScannedRepositoryState, } from "../../variant-analysis/shared/variant-analysis"; +import type { AppEvent, AppEventEmitter } from "../../common/events"; export class ModelAlertsView extends AbstractWebview< ToModelAlertsMessage, @@ -27,6 +28,9 @@ export class ModelAlertsView extends AbstractWebview< > { public static readonly viewType = "codeQL.modelAlerts"; + public readonly onEvaluationRunStopClicked: AppEvent; + private readonly onEvaluationRunStopClickedEventEmitter: AppEventEmitter; + public constructor( app: App, private readonly modelingEvents: ModelingEvents, @@ -37,6 +41,12 @@ export class ModelAlertsView extends AbstractWebview< super(app); this.registerToModelingEvents(); + + this.onEvaluationRunStopClickedEventEmitter = this.push( + app.createEventEmitter(), + ); + this.onEvaluationRunStopClicked = + this.onEvaluationRunStopClickedEventEmitter.event; } public async showView() { @@ -81,6 +91,9 @@ export class ModelAlertsView extends AbstractWebview< case "openModelPack": await this.app.commands.execute("revealInExplorer", Uri.file(msg.path)); break; + case "stopEvaluationRun": + await this.stopEvaluationRun(); + break; default: assertNever(msg); } @@ -155,4 +168,8 @@ export class ModelAlertsView extends AbstractWebview< }), ); } + + private async stopEvaluationRun() { + this.onEvaluationRunStopClickedEventEmitter.fire(); + } } diff --git a/extensions/ql-vscode/src/model-editor/model-evaluator.ts b/extensions/ql-vscode/src/model-editor/model-evaluator.ts index 8e8761c5a..21e07a11e 100644 --- a/extensions/ql-vscode/src/model-editor/model-evaluator.ts +++ b/extensions/ql-vscode/src/model-editor/model-evaluator.ts @@ -128,6 +128,10 @@ export class ModelEvaluator extends DisposableObject { ); await this.modelAlertsView.showView(); + this.modelAlertsView.onEvaluationRunStopClicked(async () => { + await this.stopEvaluation(); + }); + // There should be a variant analysis available at this point, as the // view can only opened when the variant analysis is submitted. const evaluationRun = this.modelingStore.getModelEvaluationRun( diff --git a/extensions/ql-vscode/src/stories/model-alerts/ModelAlerts.stories.tsx b/extensions/ql-vscode/src/stories/model-alerts/ModelAlerts.stories.tsx index b52c47d70..6bdee3e1b 100644 --- a/extensions/ql-vscode/src/stories/model-alerts/ModelAlerts.stories.tsx +++ b/extensions/ql-vscode/src/stories/model-alerts/ModelAlerts.stories.tsx @@ -3,7 +3,7 @@ import type { Meta, StoryFn } from "@storybook/react"; import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts"; export default { - title: "CodeQL Model Alerts/CodeQL Model Alerts", + title: "Model Alerts/Model Alerts", component: ModelAlertsComponent, } as Meta; diff --git a/extensions/ql-vscode/src/stories/model-alerts/ModelAlertsHeader.stories.tsx b/extensions/ql-vscode/src/stories/model-alerts/ModelAlertsHeader.stories.tsx new file mode 100644 index 000000000..d110ed16d --- /dev/null +++ b/extensions/ql-vscode/src/stories/model-alerts/ModelAlertsHeader.stories.tsx @@ -0,0 +1,52 @@ +import type { Meta, StoryFn } from "@storybook/react"; + +import { ModelAlertsHeader as ModelAlertsHeaderComponent } from "../../view/model-alerts/ModelAlertsHeader"; +import { createMockVariantAnalysis } from "../../../test/factories/variant-analysis/shared/variant-analysis"; + +export default { + title: "Model Alerts/Model Alerts Header", + component: ModelAlertsHeaderComponent, + argTypes: { + openModelPackClick: { + action: "open-model-pack-clicked", + table: { + disable: true, + }, + }, + stopRunClick: { + action: "stop-run-clicked", + table: { + disable: true, + }, + }, + }, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const ModelAlertsHeader = Template.bind({}); +ModelAlertsHeader.args = { + viewState: { title: "codeql/sql2o-models" }, + variantAnalysis: createMockVariantAnalysis({ + modelPacks: [ + { + name: "Model pack 1", + path: "/path/to/model-pack-1", + }, + { + name: "Model pack 2", + path: "/path/to/model-pack-2", + }, + { + name: "Model pack 3", + path: "/path/to/model-pack-3", + }, + { + name: "Model pack 4", + path: "/path/to/model-pack-4", + }, + ], + }), +}; diff --git a/extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx b/extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx index 672f27a41..5d8333878 100644 --- a/extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx +++ b/extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx @@ -21,6 +21,12 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element { }); }, []); + const onStopRunClick = useCallback(() => { + vscode.postMessage({ + t: "stopEvaluationRun", + }); + }, []); + const [viewState, setViewState] = useState( initialViewState, ); @@ -96,6 +102,7 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element { viewState={viewState} variantAnalysis={variantAnalysis} openModelPackClick={onOpenModelPackClick} + stopRunClick={onStopRunClick} >

Repo states

diff --git a/extensions/ql-vscode/src/view/model-alerts/ModelAlertsActions.tsx b/extensions/ql-vscode/src/view/model-alerts/ModelAlertsActions.tsx new file mode 100644 index 000000000..e99689634 --- /dev/null +++ b/extensions/ql-vscode/src/view/model-alerts/ModelAlertsActions.tsx @@ -0,0 +1,39 @@ +import { styled } from "styled-components"; +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import { VariantAnalysisStatus } from "../../variant-analysis/shared/variant-analysis"; + +type ModelAlertsActionsProps = { + variantAnalysisStatus: VariantAnalysisStatus; + + onStopRunClick: () => void; +}; + +const Container = styled.div` + margin-left: auto; + display: flex; + gap: 1em; +`; + +const Button = styled(VSCodeButton)` + white-space: nowrap; +`; + +export const ModelAlertsActions = ({ + variantAnalysisStatus, + onStopRunClick, +}: ModelAlertsActionsProps) => { + return ( + + {variantAnalysisStatus === VariantAnalysisStatus.InProgress && ( + + )} + {variantAnalysisStatus === VariantAnalysisStatus.Canceling && ( + + )} + + ); +}; diff --git a/extensions/ql-vscode/src/view/model-alerts/ModelAlertsHeader.tsx b/extensions/ql-vscode/src/view/model-alerts/ModelAlertsHeader.tsx index 4dad006b0..097ba05e8 100644 --- a/extensions/ql-vscode/src/view/model-alerts/ModelAlertsHeader.tsx +++ b/extensions/ql-vscode/src/view/model-alerts/ModelAlertsHeader.tsx @@ -1,26 +1,50 @@ +import { styled } from "styled-components"; import type { ModelAlertsViewState } from "../../model-editor/shared/view-state"; import type { VariantAnalysis } from "../../variant-analysis/shared/variant-analysis"; import { ViewTitle } from "../common"; +import { ModelAlertsActions } from "./ModelAlertsActions"; import { ModelPacks } from "./ModelPacks"; type Props = { viewState: ModelAlertsViewState; variantAnalysis: VariantAnalysis; openModelPackClick: (path: string) => void; + stopRunClick: () => void; }; +const Container = styled.div` + display: flex; + flex-direction: column; +`; + +const Row = styled.div` + display: flex; + align-items: flex-start; +`; + export const ModelAlertsHeader = ({ viewState, variantAnalysis, openModelPackClick, + stopRunClick, }: Props) => { return ( <> - Model evaluation results for {viewState.title} - + + + Model evaluation results for {viewState.title} + + + + + + ); }; diff --git a/extensions/ql-vscode/src/view/model-alerts/ModelPacks.tsx b/extensions/ql-vscode/src/view/model-alerts/ModelPacks.tsx index 89e65664b..13a8c0d05 100644 --- a/extensions/ql-vscode/src/view/model-alerts/ModelPacks.tsx +++ b/extensions/ql-vscode/src/view/model-alerts/ModelPacks.tsx @@ -2,6 +2,10 @@ import { styled } from "styled-components"; import { LinkIconButton } from "../common/LinkIconButton"; import type { ModelPackDetails } from "../../common/model-pack-details"; +const Container = styled.div` + display: block; +`; + const Title = styled.h3` font-size: medium; font-weight: 500; @@ -26,7 +30,7 @@ export const ModelPacks = ({ } return ( - <> + Model packs {modelPacks.map((modelPack) => ( @@ -38,6 +42,6 @@ export const ModelPacks = ({ ))} - + ); }; diff --git a/extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts b/extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts index 4ccde9eac..82e4da113 100644 --- a/extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts +++ b/extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts @@ -9,6 +9,7 @@ import { createMockScannedRepos } from "./scanned-repositories"; import { createMockSkippedRepos } from "./skipped-repositories"; import { createMockRepository } from "./repository"; import { QueryLanguage } from "../../../../src/common/query-language"; +import type { ModelPackDetails } from "../../../../src/common/model-pack-details"; export function createMockVariantAnalysis({ status = VariantAnalysisStatus.InProgress, @@ -16,12 +17,14 @@ export function createMockVariantAnalysis({ skippedRepos = createMockSkippedRepos(), executionStartTime = faker.number.int(), language = QueryLanguage.Javascript, + modelPacks = undefined, }: { status?: VariantAnalysisStatus; scannedRepos?: VariantAnalysisScannedRepository[]; skippedRepos?: VariantAnalysisSkippedRepositories; executionStartTime?: number | undefined; language?: QueryLanguage; + modelPacks?: ModelPackDetails[] | undefined; }): VariantAnalysis { return { id: faker.number.int(), @@ -37,6 +40,7 @@ export function createMockVariantAnalysis({ filePath: "a-query-file-path", text: "a-query-text", }, + modelPacks, databases: { repositories: ["1", "2", "3"], },