Skip to content

Commit 2d1c234

Browse files
authored
Add 'stop evaluation' action to Model Alerts view (#3487)
1 parent 46efb7c commit 2d1c234

File tree

10 files changed

+165
-9
lines changed

10 files changed

+165
-9
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,10 @@ interface OpenModelPackMessage {
737737
path: string;
738738
}
739739

740+
interface StopEvaluationRunMessage {
741+
t: "stopEvaluationRun";
742+
}
743+
740744
export type ToModelAlertsMessage =
741745
| SetModelAlertsViewStateMessage
742746
| SetVariantAnalysisMessage
@@ -745,4 +749,5 @@ export type ToModelAlertsMessage =
745749

746750
export type FromModelAlertsMessage =
747751
| CommonFromViewMessages
748-
| OpenModelPackMessage;
752+
| OpenModelPackMessage
753+
| StopEvaluationRunMessage;

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,17 @@ import type {
2020
VariantAnalysisScannedRepositoryResult,
2121
VariantAnalysisScannedRepositoryState,
2222
} from "../../variant-analysis/shared/variant-analysis";
23+
import type { AppEvent, AppEventEmitter } from "../../common/events";
2324

2425
export class ModelAlertsView extends AbstractWebview<
2526
ToModelAlertsMessage,
2627
FromModelAlertsMessage
2728
> {
2829
public static readonly viewType = "codeQL.modelAlerts";
2930

31+
public readonly onEvaluationRunStopClicked: AppEvent<void>;
32+
private readonly onEvaluationRunStopClickedEventEmitter: AppEventEmitter<void>;
33+
3034
public constructor(
3135
app: App,
3236
private readonly modelingEvents: ModelingEvents,
@@ -37,6 +41,12 @@ export class ModelAlertsView extends AbstractWebview<
3741
super(app);
3842

3943
this.registerToModelingEvents();
44+
45+
this.onEvaluationRunStopClickedEventEmitter = this.push(
46+
app.createEventEmitter<void>(),
47+
);
48+
this.onEvaluationRunStopClicked =
49+
this.onEvaluationRunStopClickedEventEmitter.event;
4050
}
4151

4252
public async showView() {
@@ -81,6 +91,9 @@ export class ModelAlertsView extends AbstractWebview<
8191
case "openModelPack":
8292
await this.app.commands.execute("revealInExplorer", Uri.file(msg.path));
8393
break;
94+
case "stopEvaluationRun":
95+
await this.stopEvaluationRun();
96+
break;
8497
default:
8598
assertNever(msg);
8699
}
@@ -155,4 +168,8 @@ export class ModelAlertsView extends AbstractWebview<
155168
}),
156169
);
157170
}
171+
172+
private async stopEvaluationRun() {
173+
this.onEvaluationRunStopClickedEventEmitter.fire();
174+
}
158175
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ export class ModelEvaluator extends DisposableObject {
128128
);
129129
await this.modelAlertsView.showView();
130130

131+
this.modelAlertsView.onEvaluationRunStopClicked(async () => {
132+
await this.stopEvaluation();
133+
});
134+
131135
// There should be a variant analysis available at this point, as the
132136
// view can only opened when the variant analysis is submitted.
133137
const evaluationRun = this.modelingStore.getModelEvaluationRun(

extensions/ql-vscode/src/stories/model-alerts/ModelAlerts.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Meta, StoryFn } from "@storybook/react";
33
import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts";
44

55
export default {
6-
title: "CodeQL Model Alerts/CodeQL Model Alerts",
6+
title: "Model Alerts/Model Alerts",
77
component: ModelAlertsComponent,
88
} as Meta<typeof ModelAlertsComponent>;
99

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { Meta, StoryFn } from "@storybook/react";
2+
3+
import { ModelAlertsHeader as ModelAlertsHeaderComponent } from "../../view/model-alerts/ModelAlertsHeader";
4+
import { createMockVariantAnalysis } from "../../../test/factories/variant-analysis/shared/variant-analysis";
5+
6+
export default {
7+
title: "Model Alerts/Model Alerts Header",
8+
component: ModelAlertsHeaderComponent,
9+
argTypes: {
10+
openModelPackClick: {
11+
action: "open-model-pack-clicked",
12+
table: {
13+
disable: true,
14+
},
15+
},
16+
stopRunClick: {
17+
action: "stop-run-clicked",
18+
table: {
19+
disable: true,
20+
},
21+
},
22+
},
23+
} as Meta<typeof ModelAlertsHeaderComponent>;
24+
25+
const Template: StoryFn<typeof ModelAlertsHeaderComponent> = (args) => (
26+
<ModelAlertsHeaderComponent {...args} />
27+
);
28+
29+
export const ModelAlertsHeader = Template.bind({});
30+
ModelAlertsHeader.args = {
31+
viewState: { title: "codeql/sql2o-models" },
32+
variantAnalysis: createMockVariantAnalysis({
33+
modelPacks: [
34+
{
35+
name: "Model pack 1",
36+
path: "/path/to/model-pack-1",
37+
},
38+
{
39+
name: "Model pack 2",
40+
path: "/path/to/model-pack-2",
41+
},
42+
{
43+
name: "Model pack 3",
44+
path: "/path/to/model-pack-3",
45+
},
46+
{
47+
name: "Model pack 4",
48+
path: "/path/to/model-pack-4",
49+
},
50+
],
51+
}),
52+
};

extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element {
2121
});
2222
}, []);
2323

24+
const onStopRunClick = useCallback(() => {
25+
vscode.postMessage({
26+
t: "stopEvaluationRun",
27+
});
28+
}, []);
29+
2430
const [viewState, setViewState] = useState<ModelAlertsViewState | undefined>(
2531
initialViewState,
2632
);
@@ -96,6 +102,7 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element {
96102
viewState={viewState}
97103
variantAnalysis={variantAnalysis}
98104
openModelPackClick={onOpenModelPackClick}
105+
stopRunClick={onStopRunClick}
99106
></ModelAlertsHeader>
100107
<div>
101108
<h3>Repo states</h3>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { styled } from "styled-components";
2+
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react";
3+
import { VariantAnalysisStatus } from "../../variant-analysis/shared/variant-analysis";
4+
5+
type ModelAlertsActionsProps = {
6+
variantAnalysisStatus: VariantAnalysisStatus;
7+
8+
onStopRunClick: () => void;
9+
};
10+
11+
const Container = styled.div`
12+
margin-left: auto;
13+
display: flex;
14+
gap: 1em;
15+
`;
16+
17+
const Button = styled(VSCodeButton)`
18+
white-space: nowrap;
19+
`;
20+
21+
export const ModelAlertsActions = ({
22+
variantAnalysisStatus,
23+
onStopRunClick,
24+
}: ModelAlertsActionsProps) => {
25+
return (
26+
<Container>
27+
{variantAnalysisStatus === VariantAnalysisStatus.InProgress && (
28+
<Button appearance="secondary" onClick={onStopRunClick}>
29+
Stop evaluation
30+
</Button>
31+
)}
32+
{variantAnalysisStatus === VariantAnalysisStatus.Canceling && (
33+
<Button appearance="secondary" disabled={true}>
34+
Stopping evaluation
35+
</Button>
36+
)}
37+
</Container>
38+
);
39+
};
Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,50 @@
1+
import { styled } from "styled-components";
12
import type { ModelAlertsViewState } from "../../model-editor/shared/view-state";
23
import type { VariantAnalysis } from "../../variant-analysis/shared/variant-analysis";
34
import { ViewTitle } from "../common";
5+
import { ModelAlertsActions } from "./ModelAlertsActions";
46
import { ModelPacks } from "./ModelPacks";
57

68
type Props = {
79
viewState: ModelAlertsViewState;
810
variantAnalysis: VariantAnalysis;
911
openModelPackClick: (path: string) => void;
12+
stopRunClick: () => void;
1013
};
1114

15+
const Container = styled.div`
16+
display: flex;
17+
flex-direction: column;
18+
`;
19+
20+
const Row = styled.div`
21+
display: flex;
22+
align-items: flex-start;
23+
`;
24+
1225
export const ModelAlertsHeader = ({
1326
viewState,
1427
variantAnalysis,
1528
openModelPackClick,
29+
stopRunClick,
1630
}: Props) => {
1731
return (
1832
<>
19-
<ViewTitle>Model evaluation results for {viewState.title}</ViewTitle>
20-
<ModelPacks
21-
modelPacks={variantAnalysis.modelPacks || []}
22-
openModelPackClick={openModelPackClick}
23-
></ModelPacks>
33+
<Container>
34+
<Row>
35+
<ViewTitle>Model evaluation results for {viewState.title}</ViewTitle>
36+
</Row>
37+
<Row>
38+
<ModelPacks
39+
modelPacks={variantAnalysis.modelPacks || []}
40+
openModelPackClick={openModelPackClick}
41+
></ModelPacks>
42+
<ModelAlertsActions
43+
variantAnalysisStatus={variantAnalysis.status}
44+
onStopRunClick={stopRunClick}
45+
/>
46+
</Row>
47+
</Container>
2448
</>
2549
);
2650
};

extensions/ql-vscode/src/view/model-alerts/ModelPacks.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { styled } from "styled-components";
22
import { LinkIconButton } from "../common/LinkIconButton";
33
import type { ModelPackDetails } from "../../common/model-pack-details";
44

5+
const Container = styled.div`
6+
display: block;
7+
`;
8+
59
const Title = styled.h3`
610
font-size: medium;
711
font-weight: 500;
@@ -26,7 +30,7 @@ export const ModelPacks = ({
2630
}
2731

2832
return (
29-
<>
33+
<Container>
3034
<Title>Model packs</Title>
3135
<List>
3236
{modelPacks.map((modelPack) => (
@@ -38,6 +42,6 @@ export const ModelPacks = ({
3842
</li>
3943
))}
4044
</List>
41-
</>
45+
</Container>
4246
);
4347
};

extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ import { createMockScannedRepos } from "./scanned-repositories";
99
import { createMockSkippedRepos } from "./skipped-repositories";
1010
import { createMockRepository } from "./repository";
1111
import { QueryLanguage } from "../../../../src/common/query-language";
12+
import type { ModelPackDetails } from "../../../../src/common/model-pack-details";
1213

1314
export function createMockVariantAnalysis({
1415
status = VariantAnalysisStatus.InProgress,
1516
scannedRepos = createMockScannedRepos(),
1617
skippedRepos = createMockSkippedRepos(),
1718
executionStartTime = faker.number.int(),
1819
language = QueryLanguage.Javascript,
20+
modelPacks = undefined,
1921
}: {
2022
status?: VariantAnalysisStatus;
2123
scannedRepos?: VariantAnalysisScannedRepository[];
2224
skippedRepos?: VariantAnalysisSkippedRepositories;
2325
executionStartTime?: number | undefined;
2426
language?: QueryLanguage;
27+
modelPacks?: ModelPackDetails[] | undefined;
2528
}): VariantAnalysis {
2629
return {
2730
id: faker.number.int(),
@@ -37,6 +40,7 @@ export function createMockVariantAnalysis({
3740
filePath: "a-query-file-path",
3841
text: "a-query-text",
3942
},
43+
modelPacks,
4044
databases: {
4145
repositories: ["1", "2", "3"],
4246
},

0 commit comments

Comments
 (0)