Only allow one open model alerts view (#3461)
This commit is contained in:
@@ -11,6 +11,9 @@ import type { App } from "../../common/app";
|
||||
import { redactableError } from "../../common/errors";
|
||||
import { extLogger } from "../../common/logging/vscode";
|
||||
import { showAndLogExceptionWithTelemetry } from "../../common/logging";
|
||||
import type { ModelingEvents } from "../modeling-events";
|
||||
import type { ModelingStore } from "../modeling-store";
|
||||
import type { DatabaseItem } from "../../databases/local-databases";
|
||||
|
||||
export class ModelAlertsView extends AbstractWebview<
|
||||
ToModelAlertsMessage,
|
||||
@@ -18,8 +21,15 @@ export class ModelAlertsView extends AbstractWebview<
|
||||
> {
|
||||
public static readonly viewType = "codeQL.modelAlerts";
|
||||
|
||||
public constructor(app: App) {
|
||||
public constructor(
|
||||
app: App,
|
||||
private readonly modelingEvents: ModelingEvents,
|
||||
private readonly modelingStore: ModelingStore,
|
||||
private readonly dbItem: DatabaseItem,
|
||||
) {
|
||||
super(app);
|
||||
|
||||
this.registerToModelingEvents();
|
||||
}
|
||||
|
||||
public async showView() {
|
||||
@@ -40,7 +50,7 @@ export class ModelAlertsView extends AbstractWebview<
|
||||
}
|
||||
|
||||
protected onPanelDispose(): void {
|
||||
// Nothing to dispose
|
||||
this.modelingStore.updateIsModelAlertsViewOpen(this.dbItem, false);
|
||||
}
|
||||
|
||||
protected async onMessage(msg: FromModelAlertsMessage): Promise<void> {
|
||||
@@ -64,4 +74,18 @@ export class ModelAlertsView extends AbstractWebview<
|
||||
assertNever(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public async focusView(): Promise<void> {
|
||||
this.panel?.reveal();
|
||||
}
|
||||
|
||||
private registerToModelingEvents() {
|
||||
this.push(
|
||||
this.modelingEvents.onFocusModelAlertsView(async (event) => {
|
||||
if (event.dbUri === this.dbItem.databaseUri.toString()) {
|
||||
await this.focusView();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +107,21 @@ export class ModelEvaluator extends DisposableObject {
|
||||
}
|
||||
|
||||
public async openModelAlertsView() {
|
||||
const view = new ModelAlertsView(this.app);
|
||||
await view.showView();
|
||||
if (this.modelingStore.isModelAlertsViewOpen(this.dbItem)) {
|
||||
this.modelingEvents.fireFocusModelAlertsViewEvent(
|
||||
this.dbItem.databaseUri.toString(),
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
this.modelingStore.updateIsModelAlertsViewOpen(this.dbItem, true);
|
||||
const view = new ModelAlertsView(
|
||||
this.app,
|
||||
this.modelingEvents,
|
||||
this.modelingStore,
|
||||
this.dbItem,
|
||||
);
|
||||
await view.showView();
|
||||
}
|
||||
}
|
||||
|
||||
private registerToModelingEvents() {
|
||||
|
||||
@@ -65,6 +65,10 @@ interface FocusModelEditorEvent {
|
||||
dbUri: string;
|
||||
}
|
||||
|
||||
interface FocusModelAlertsViewEvent {
|
||||
dbUri: string;
|
||||
}
|
||||
|
||||
export class ModelingEvents extends DisposableObject {
|
||||
public readonly onActiveDbChanged: AppEvent<void>;
|
||||
public readonly onDbOpened: AppEvent<DatabaseItem>;
|
||||
@@ -79,6 +83,7 @@ export class ModelingEvents extends DisposableObject {
|
||||
public readonly onModelEvaluationRunChanged: AppEvent<ModelEvaluationRunChangedEvent>;
|
||||
public readonly onRevealInModelEditor: AppEvent<RevealInModelEditorEvent>;
|
||||
public readonly onFocusModelEditor: AppEvent<FocusModelEditorEvent>;
|
||||
public readonly onFocusModelAlertsView: AppEvent<FocusModelAlertsViewEvent>;
|
||||
|
||||
private readonly onActiveDbChangedEventEmitter: AppEventEmitter<void>;
|
||||
private readonly onDbOpenedEventEmitter: AppEventEmitter<DatabaseItem>;
|
||||
@@ -93,6 +98,7 @@ export class ModelingEvents extends DisposableObject {
|
||||
private readonly onModelEvaluationRunChangedEventEmitter: AppEventEmitter<ModelEvaluationRunChangedEvent>;
|
||||
private readonly onRevealInModelEditorEventEmitter: AppEventEmitter<RevealInModelEditorEvent>;
|
||||
private readonly onFocusModelEditorEventEmitter: AppEventEmitter<FocusModelEditorEvent>;
|
||||
private readonly onFocusModelAlertsViewEventEmitter: AppEventEmitter<FocusModelAlertsViewEvent>;
|
||||
|
||||
constructor(app: App) {
|
||||
super();
|
||||
@@ -165,6 +171,11 @@ export class ModelingEvents extends DisposableObject {
|
||||
app.createEventEmitter<FocusModelEditorEvent>(),
|
||||
);
|
||||
this.onFocusModelEditor = this.onFocusModelEditorEventEmitter.event;
|
||||
|
||||
this.onFocusModelAlertsViewEventEmitter = this.push(
|
||||
app.createEventEmitter<FocusModelAlertsViewEvent>(),
|
||||
);
|
||||
this.onFocusModelAlertsView = this.onFocusModelAlertsViewEventEmitter.event;
|
||||
}
|
||||
|
||||
public fireActiveDbChangedEvent() {
|
||||
@@ -286,4 +297,8 @@ export class ModelingEvents extends DisposableObject {
|
||||
dbUri,
|
||||
});
|
||||
}
|
||||
|
||||
public fireFocusModelAlertsViewEvent(dbUri: string) {
|
||||
this.onFocusModelAlertsViewEventEmitter.fire({ dbUri });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ interface InternalDbModelingState {
|
||||
selectedMethod: Method | undefined;
|
||||
selectedUsage: Usage | undefined;
|
||||
modelEvaluationRun: ModelEvaluationRun | undefined;
|
||||
isModelAlertsViewOpen: boolean;
|
||||
}
|
||||
|
||||
export interface DbModelingState {
|
||||
@@ -34,6 +35,7 @@ export interface DbModelingState {
|
||||
readonly selectedMethod: Method | undefined;
|
||||
readonly selectedUsage: Usage | undefined;
|
||||
readonly modelEvaluationRun: ModelEvaluationRun | undefined;
|
||||
readonly isModelAlertsViewOpen: boolean;
|
||||
}
|
||||
|
||||
export interface SelectedMethodDetails {
|
||||
@@ -71,6 +73,7 @@ export class ModelingStore extends DisposableObject {
|
||||
selectedUsage: undefined,
|
||||
inProgressMethods: new Set(),
|
||||
modelEvaluationRun: undefined,
|
||||
isModelAlertsViewOpen: false,
|
||||
});
|
||||
|
||||
this.modelingEvents.fireDbOpenedEvent(databaseItem);
|
||||
@@ -498,4 +501,23 @@ export class ModelingStore extends DisposableObject {
|
||||
state.modelEvaluationRun,
|
||||
);
|
||||
}
|
||||
|
||||
public isModelAlertsViewOpen(dbItem: DatabaseItem): boolean {
|
||||
return this.getState(dbItem).isModelAlertsViewOpen ?? false;
|
||||
}
|
||||
|
||||
private changeIsModelAlertsViewOpen(
|
||||
dbItem: DatabaseItem,
|
||||
updateState: (state: InternalDbModelingState) => void,
|
||||
) {
|
||||
const state = this.getState(dbItem);
|
||||
|
||||
updateState(state);
|
||||
}
|
||||
|
||||
public updateIsModelAlertsViewOpen(dbItem: DatabaseItem, isOpen: boolean) {
|
||||
this.changeIsModelAlertsViewOpen(dbItem, (state) => {
|
||||
state.isModelAlertsViewOpen = isOpen;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ export const ModelEvaluation = ({
|
||||
|
||||
const shouldShowStopButton = !shouldShowEvaluateButton;
|
||||
|
||||
const shouldShowEvaluationRunLink = !!evaluationRun;
|
||||
const shouldShowEvaluationRunLink =
|
||||
!!evaluationRun && evaluationRun.variantAnalysis;
|
||||
|
||||
const customModelsExist = Object.values(modeledMethods).some(
|
||||
(methods) => methods.filter((m) => m.type !== "none").length > 0,
|
||||
|
||||
@@ -98,7 +98,7 @@ describe(ModelEvaluation.name, () => {
|
||||
expect(screen.queryByText("Stop evaluation")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders 'Stop evaluation' button and 'Evaluation run' link when there is an in progress evaluation", () => {
|
||||
it("renders 'Stop evaluation' button when there is an in progress evaluation, but no variant analysis yet", () => {
|
||||
render({
|
||||
evaluationRun: {
|
||||
isPreparing: true,
|
||||
@@ -112,6 +112,27 @@ describe(ModelEvaluation.name, () => {
|
||||
stopEvaluationButton?.getElementsByTagName("input")[0],
|
||||
).toBeEnabled();
|
||||
|
||||
expect(screen.queryByText("Evaluation run")).not.toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText("Evaluate")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders 'Stop evaluation' button and 'Evaluation run' link when there is an in progress evaluation with variant analysis", () => {
|
||||
render({
|
||||
evaluationRun: {
|
||||
isPreparing: false,
|
||||
variantAnalysis: createMockVariantAnalysis({
|
||||
status: VariantAnalysisStatus.InProgress,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const stopEvaluationButton = screen.queryByText("Stop evaluation");
|
||||
expect(stopEvaluationButton).toBeInTheDocument();
|
||||
expect(
|
||||
stopEvaluationButton?.getElementsByTagName("input")[0],
|
||||
).toBeEnabled();
|
||||
|
||||
expect(screen.queryByText("Evaluation run")).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText("Evaluate")).not.toBeInTheDocument();
|
||||
|
||||
Reference in New Issue
Block a user