Add 'stop evaluation' action to Model Alerts view (#3487)

This commit is contained in:
Charis Kyriakou 2024-03-18 15:41:33 +00:00 коммит произвёл GitHub
Родитель 46efb7c971
Коммит 2d1c2349f8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 165 добавлений и 9 удалений

Просмотреть файл

@ -737,6 +737,10 @@ interface OpenModelPackMessage {
path: string; path: string;
} }
interface StopEvaluationRunMessage {
t: "stopEvaluationRun";
}
export type ToModelAlertsMessage = export type ToModelAlertsMessage =
| SetModelAlertsViewStateMessage | SetModelAlertsViewStateMessage
| SetVariantAnalysisMessage | SetVariantAnalysisMessage
@ -745,4 +749,5 @@ export type ToModelAlertsMessage =
export type FromModelAlertsMessage = export type FromModelAlertsMessage =
| CommonFromViewMessages | CommonFromViewMessages
| OpenModelPackMessage; | OpenModelPackMessage
| StopEvaluationRunMessage;

Просмотреть файл

@ -20,6 +20,7 @@ import type {
VariantAnalysisScannedRepositoryResult, VariantAnalysisScannedRepositoryResult,
VariantAnalysisScannedRepositoryState, VariantAnalysisScannedRepositoryState,
} from "../../variant-analysis/shared/variant-analysis"; } from "../../variant-analysis/shared/variant-analysis";
import type { AppEvent, AppEventEmitter } from "../../common/events";
export class ModelAlertsView extends AbstractWebview< export class ModelAlertsView extends AbstractWebview<
ToModelAlertsMessage, ToModelAlertsMessage,
@ -27,6 +28,9 @@ export class ModelAlertsView extends AbstractWebview<
> { > {
public static readonly viewType = "codeQL.modelAlerts"; public static readonly viewType = "codeQL.modelAlerts";
public readonly onEvaluationRunStopClicked: AppEvent<void>;
private readonly onEvaluationRunStopClickedEventEmitter: AppEventEmitter<void>;
public constructor( public constructor(
app: App, app: App,
private readonly modelingEvents: ModelingEvents, private readonly modelingEvents: ModelingEvents,
@ -37,6 +41,12 @@ export class ModelAlertsView extends AbstractWebview<
super(app); super(app);
this.registerToModelingEvents(); this.registerToModelingEvents();
this.onEvaluationRunStopClickedEventEmitter = this.push(
app.createEventEmitter<void>(),
);
this.onEvaluationRunStopClicked =
this.onEvaluationRunStopClickedEventEmitter.event;
} }
public async showView() { public async showView() {
@ -81,6 +91,9 @@ export class ModelAlertsView extends AbstractWebview<
case "openModelPack": case "openModelPack":
await this.app.commands.execute("revealInExplorer", Uri.file(msg.path)); await this.app.commands.execute("revealInExplorer", Uri.file(msg.path));
break; break;
case "stopEvaluationRun":
await this.stopEvaluationRun();
break;
default: default:
assertNever(msg); assertNever(msg);
} }
@ -155,4 +168,8 @@ export class ModelAlertsView extends AbstractWebview<
}), }),
); );
} }
private async stopEvaluationRun() {
this.onEvaluationRunStopClickedEventEmitter.fire();
}
} }

Просмотреть файл

@ -128,6 +128,10 @@ export class ModelEvaluator extends DisposableObject {
); );
await this.modelAlertsView.showView(); await this.modelAlertsView.showView();
this.modelAlertsView.onEvaluationRunStopClicked(async () => {
await this.stopEvaluation();
});
// There should be a variant analysis available at this point, as the // There should be a variant analysis available at this point, as the
// view can only opened when the variant analysis is submitted. // view can only opened when the variant analysis is submitted.
const evaluationRun = this.modelingStore.getModelEvaluationRun( const evaluationRun = this.modelingStore.getModelEvaluationRun(

Просмотреть файл

@ -3,7 +3,7 @@ import type { Meta, StoryFn } from "@storybook/react";
import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts"; import { ModelAlerts as ModelAlertsComponent } from "../../view/model-alerts/ModelAlerts";
export default { export default {
title: "CodeQL Model Alerts/CodeQL Model Alerts", title: "Model Alerts/Model Alerts",
component: ModelAlertsComponent, component: ModelAlertsComponent,
} as Meta<typeof ModelAlertsComponent>; } as Meta<typeof ModelAlertsComponent>;

Просмотреть файл

@ -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<typeof ModelAlertsHeaderComponent>;
const Template: StoryFn<typeof ModelAlertsHeaderComponent> = (args) => (
<ModelAlertsHeaderComponent {...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",
},
],
}),
};

Просмотреть файл

@ -21,6 +21,12 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element {
}); });
}, []); }, []);
const onStopRunClick = useCallback(() => {
vscode.postMessage({
t: "stopEvaluationRun",
});
}, []);
const [viewState, setViewState] = useState<ModelAlertsViewState | undefined>( const [viewState, setViewState] = useState<ModelAlertsViewState | undefined>(
initialViewState, initialViewState,
); );
@ -96,6 +102,7 @@ export function ModelAlerts({ initialViewState }: Props): React.JSX.Element {
viewState={viewState} viewState={viewState}
variantAnalysis={variantAnalysis} variantAnalysis={variantAnalysis}
openModelPackClick={onOpenModelPackClick} openModelPackClick={onOpenModelPackClick}
stopRunClick={onStopRunClick}
></ModelAlertsHeader> ></ModelAlertsHeader>
<div> <div>
<h3>Repo states</h3> <h3>Repo states</h3>

Просмотреть файл

@ -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 (
<Container>
{variantAnalysisStatus === VariantAnalysisStatus.InProgress && (
<Button appearance="secondary" onClick={onStopRunClick}>
Stop evaluation
</Button>
)}
{variantAnalysisStatus === VariantAnalysisStatus.Canceling && (
<Button appearance="secondary" disabled={true}>
Stopping evaluation
</Button>
)}
</Container>
);
};

Просмотреть файл

@ -1,26 +1,50 @@
import { styled } from "styled-components";
import type { ModelAlertsViewState } from "../../model-editor/shared/view-state"; import type { ModelAlertsViewState } from "../../model-editor/shared/view-state";
import type { VariantAnalysis } from "../../variant-analysis/shared/variant-analysis"; import type { VariantAnalysis } from "../../variant-analysis/shared/variant-analysis";
import { ViewTitle } from "../common"; import { ViewTitle } from "../common";
import { ModelAlertsActions } from "./ModelAlertsActions";
import { ModelPacks } from "./ModelPacks"; import { ModelPacks } from "./ModelPacks";
type Props = { type Props = {
viewState: ModelAlertsViewState; viewState: ModelAlertsViewState;
variantAnalysis: VariantAnalysis; variantAnalysis: VariantAnalysis;
openModelPackClick: (path: string) => void; 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 = ({ export const ModelAlertsHeader = ({
viewState, viewState,
variantAnalysis, variantAnalysis,
openModelPackClick, openModelPackClick,
stopRunClick,
}: Props) => { }: Props) => {
return ( return (
<> <>
<ViewTitle>Model evaluation results for {viewState.title}</ViewTitle> <Container>
<ModelPacks <Row>
modelPacks={variantAnalysis.modelPacks || []} <ViewTitle>Model evaluation results for {viewState.title}</ViewTitle>
openModelPackClick={openModelPackClick} </Row>
></ModelPacks> <Row>
<ModelPacks
modelPacks={variantAnalysis.modelPacks || []}
openModelPackClick={openModelPackClick}
></ModelPacks>
<ModelAlertsActions
variantAnalysisStatus={variantAnalysis.status}
onStopRunClick={stopRunClick}
/>
</Row>
</Container>
</> </>
); );
}; };

Просмотреть файл

@ -2,6 +2,10 @@ import { styled } from "styled-components";
import { LinkIconButton } from "../common/LinkIconButton"; import { LinkIconButton } from "../common/LinkIconButton";
import type { ModelPackDetails } from "../../common/model-pack-details"; import type { ModelPackDetails } from "../../common/model-pack-details";
const Container = styled.div`
display: block;
`;
const Title = styled.h3` const Title = styled.h3`
font-size: medium; font-size: medium;
font-weight: 500; font-weight: 500;
@ -26,7 +30,7 @@ export const ModelPacks = ({
} }
return ( return (
<> <Container>
<Title>Model packs</Title> <Title>Model packs</Title>
<List> <List>
{modelPacks.map((modelPack) => ( {modelPacks.map((modelPack) => (
@ -38,6 +42,6 @@ export const ModelPacks = ({
</li> </li>
))} ))}
</List> </List>
</> </Container>
); );
}; };

Просмотреть файл

@ -9,6 +9,7 @@ import { createMockScannedRepos } from "./scanned-repositories";
import { createMockSkippedRepos } from "./skipped-repositories"; import { createMockSkippedRepos } from "./skipped-repositories";
import { createMockRepository } from "./repository"; import { createMockRepository } from "./repository";
import { QueryLanguage } from "../../../../src/common/query-language"; import { QueryLanguage } from "../../../../src/common/query-language";
import type { ModelPackDetails } from "../../../../src/common/model-pack-details";
export function createMockVariantAnalysis({ export function createMockVariantAnalysis({
status = VariantAnalysisStatus.InProgress, status = VariantAnalysisStatus.InProgress,
@ -16,12 +17,14 @@ export function createMockVariantAnalysis({
skippedRepos = createMockSkippedRepos(), skippedRepos = createMockSkippedRepos(),
executionStartTime = faker.number.int(), executionStartTime = faker.number.int(),
language = QueryLanguage.Javascript, language = QueryLanguage.Javascript,
modelPacks = undefined,
}: { }: {
status?: VariantAnalysisStatus; status?: VariantAnalysisStatus;
scannedRepos?: VariantAnalysisScannedRepository[]; scannedRepos?: VariantAnalysisScannedRepository[];
skippedRepos?: VariantAnalysisSkippedRepositories; skippedRepos?: VariantAnalysisSkippedRepositories;
executionStartTime?: number | undefined; executionStartTime?: number | undefined;
language?: QueryLanguage; language?: QueryLanguage;
modelPacks?: ModelPackDetails[] | undefined;
}): VariantAnalysis { }): VariantAnalysis {
return { return {
id: faker.number.int(), id: faker.number.int(),
@ -37,6 +40,7 @@ export function createMockVariantAnalysis({
filePath: "a-query-file-path", filePath: "a-query-file-path",
text: "a-query-text", text: "a-query-text",
}, },
modelPacks,
databases: { databases: {
repositories: ["1", "2", "3"], repositories: ["1", "2", "3"],
}, },