Replace ModelEditorViewTracker with modeling store and events (#3065)

This commit is contained in:
Charis Kyriakou
2023-11-14 11:38:28 +00:00
committed by GitHub
parent 9e914c9ba1
commit be2891dfba
10 changed files with 79 additions and 102 deletions

View File

@@ -4,7 +4,6 @@ import { DisposableObject } from "../../common/disposable-object";
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
import { Method } from "../method";
import { ModelingStore } from "../modeling-store";
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
import { ModelConfigListener } from "../../config";
import { DatabaseItem } from "../../databases/local-databases";
import { ModelingEvents } from "../modeling-events";
@@ -16,7 +15,6 @@ export class MethodModelingPanel extends DisposableObject {
app: App,
modelingStore: ModelingStore,
modelingEvents: ModelingEvents,
editorViewTracker: ModelEditorViewTracker,
) {
super();
@@ -29,7 +27,6 @@ export class MethodModelingPanel extends DisposableObject {
app,
modelingStore,
modelingEvents,
editorViewTracker,
modelConfig,
);
this.push(

View File

@@ -10,7 +10,6 @@ import { Method } from "../method";
import { ModelingStore } from "../modeling-store";
import { AbstractWebviewViewProvider } from "../../common/vscode/abstract-webview-view-provider";
import { assertNever } from "../../common/helpers-pure";
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
import { ModelConfigListener } from "../../config";
import { DatabaseItem } from "../../databases/local-databases";
import { ModelingEvents } from "../modeling-events";
@@ -33,7 +32,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
app: App,
private readonly modelingStore: ModelingStore,
private readonly modelingEvents: ModelingEvents,
private readonly editorViewTracker: ModelEditorViewTracker,
private readonly modelConfig: ModelConfigListener,
) {
super(app, "method-modeling");
@@ -158,10 +156,10 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
return;
}
const view = this.editorViewTracker.getView(
this.modelingEvents.fireRevealInModelEditorEvent(
this.databaseItem.databaseUri.toString(),
method,
);
await view?.revealMethod(method);
}
private registerToModelingEvents(): void {

View File

@@ -19,7 +19,6 @@ import { setUpPack } from "./model-editor-queries-setup";
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
import { ModelingStore } from "./modeling-store";
import { showResolvableLocation } from "../databases/local-databases/locations";
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
import { ModelConfigListener } from "../config";
import { ModelingEvents } from "./modeling-events";
import { getModelsAsDataLanguage } from "./languages";
@@ -30,7 +29,6 @@ export class ModelEditorModule extends DisposableObject {
private readonly queryStorageDir: string;
private readonly modelingStore: ModelingStore;
private readonly modelingEvents: ModelingEvents;
private readonly editorViewTracker: ModelEditorViewTracker<ModelEditorView>;
private readonly methodsUsagePanel: MethodsUsagePanel;
private readonly methodModelingPanel: MethodModelingPanel;
private readonly modelConfig: ModelConfigListener;
@@ -46,17 +44,11 @@ export class ModelEditorModule extends DisposableObject {
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
this.modelingEvents = new ModelingEvents(app);
this.modelingStore = new ModelingStore(this.modelingEvents);
this.editorViewTracker = new ModelEditorViewTracker();
this.methodsUsagePanel = this.push(
new MethodsUsagePanel(this.modelingStore, this.modelingEvents, cliServer),
);
this.methodModelingPanel = this.push(
new MethodModelingPanel(
app,
this.modelingStore,
this.modelingEvents,
this.editorViewTracker,
),
new MethodModelingPanel(app, this.modelingStore, this.modelingEvents),
);
this.modelConfig = this.push(new ModelConfigListener());
@@ -144,12 +136,10 @@ export class ModelEditorModule extends DisposableObject {
const initialMode = definition.availableModes?.[0] ?? INITIAL_MODE;
const existingView = this.editorViewTracker.getView(
db.databaseUri.toString(),
);
if (existingView) {
await existingView.focusView();
if (this.modelingStore.isDbOpen(db.databaseUri.toString())) {
this.modelingEvents.fireFocusModelEditorEvent(
db.databaseUri.toString(),
);
return;
}
@@ -218,12 +208,10 @@ export class ModelEditorModule extends DisposableObject {
// Check again just before opening the editor to ensure no model editor has been opened between
// our first check and now.
const existingView = this.editorViewTracker.getView(
db.databaseUri.toString(),
);
if (existingView) {
await existingView.focusView();
if (this.modelingStore.isDbOpen(db.databaseUri.toString())) {
this.modelingEvents.fireFocusModelEditorEvent(
db.databaseUri.toString(),
);
return;
}
@@ -231,7 +219,6 @@ export class ModelEditorModule extends DisposableObject {
this.app,
this.modelingStore,
this.modelingEvents,
this.editorViewTracker,
this.modelConfig,
this.databaseManager,
this.cliServer,

View File

@@ -1,33 +0,0 @@
import { Method } from "./method";
interface ModelEditorViewInterface {
databaseUri: string;
revealMethod(method: Method): Promise<void>;
}
export class ModelEditorViewTracker<
T extends ModelEditorViewInterface = ModelEditorViewInterface,
> {
private readonly views = new Map<string, T>();
constructor() {}
public registerView(view: T): void {
const databaseUri = view.databaseUri;
if (this.views.has(databaseUri)) {
throw new Error(`View for database ${databaseUri} already registered`);
}
this.views.set(databaseUri, view);
}
public unregisterView(view: T): void {
this.views.delete(view.databaseUri);
}
public getView(databaseUri: string): T | undefined {
return this.views.get(databaseUri);
}
}

View File

@@ -44,7 +44,6 @@ import {
import { AutoModeler } from "./auto-modeler";
import { telemetryListener } from "../common/vscode/telemetry";
import { ModelingStore } from "./modeling-store";
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
import { ModelingEvents } from "./modeling-events";
import { getModelsAsDataLanguage, ModelsAsDataLanguage } from "./languages";
import { runGenerateQueries } from "./generate";
@@ -60,7 +59,6 @@ export class ModelEditorView extends AbstractWebview<
protected readonly app: App,
private readonly modelingStore: ModelingStore,
private readonly modelingEvents: ModelingEvents,
private readonly viewTracker: ModelEditorViewTracker<ModelEditorView>,
private readonly modelConfig: ModelConfigListener,
private readonly databaseManager: DatabaseManager,
private readonly cliServer: CodeQLCliServer,
@@ -79,8 +77,6 @@ export class ModelEditorView extends AbstractWebview<
this.registerToModelingEvents();
this.registerToModelConfigEvents();
this.viewTracker.registerView(this);
this.autoModeler = new AutoModeler(
app,
cliServer,
@@ -166,7 +162,7 @@ export class ModelEditorView extends AbstractWebview<
}
protected onPanelDispose(): void {
this.viewTracker.unregisterView(this);
// Nothing to do
}
protected async onMessage(msg: FromModelEditorMessage): Promise<void> {
@@ -573,12 +569,9 @@ export class ModelEditorView extends AbstractWebview<
return;
}
let existingView = this.viewTracker.getView(
addedDatabase.databaseUri.toString(),
);
if (existingView) {
await existingView.focusView();
const addedDbUri = addedDatabase.databaseUri.toString();
if (this.modelingStore.isDbOpen(addedDbUri)) {
this.modelingEvents.fireFocusModelEditorEvent(addedDbUri);
return;
}
@@ -596,12 +589,8 @@ export class ModelEditorView extends AbstractWebview<
// Check again just before opening the editor to ensure no model editor has been opened between
// our first check and now.
existingView = this.viewTracker.getView(
addedDatabase.databaseUri.toString(),
);
if (existingView) {
await existingView.focusView();
if (this.modelingStore.isDbOpen(addedDbUri)) {
this.modelingEvents.fireFocusModelEditorEvent(addedDbUri);
return;
}
@@ -609,7 +598,6 @@ export class ModelEditorView extends AbstractWebview<
this.app,
this.modelingStore,
this.modelingEvents,
this.viewTracker,
this.modelConfig,
this.databaseManager,
this.cliServer,
@@ -742,6 +730,22 @@ export class ModelEditorView extends AbstractWebview<
}
}),
);
this.push(
this.modelingEvents.onRevealInModelEditor(async (event) => {
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
await this.revealMethod(event.method);
}
}),
);
this.push(
this.modelingEvents.onFocusModelEditor(async (event) => {
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
await this.focusView();
}
}),
);
}
private registerToModelConfigEvents() {

View File

@@ -48,6 +48,15 @@ interface InProgressMethodsChangedEvent {
readonly methods: ReadonlySet<string>;
}
interface RevealInModelEditorEvent {
dbUri: string;
method: Method;
}
interface FocusModelEditorEvent {
dbUri: string;
}
export class ModelingEvents extends DisposableObject {
public readonly onActiveDbChanged: AppEvent<void>;
public readonly onDbOpened: AppEvent<DatabaseItem>;
@@ -59,6 +68,8 @@ export class ModelingEvents extends DisposableObject {
public readonly onModifiedMethodsChanged: AppEvent<ModifiedMethodsChangedEvent>;
public readonly onSelectedMethodChanged: AppEvent<SelectedMethodChangedEvent>;
public readonly onInProgressMethodsChanged: AppEvent<InProgressMethodsChangedEvent>;
public readonly onRevealInModelEditor: AppEvent<RevealInModelEditorEvent>;
public readonly onFocusModelEditor: AppEvent<FocusModelEditorEvent>;
private readonly onActiveDbChangedEventEmitter: AppEventEmitter<void>;
private readonly onDbOpenedEventEmitter: AppEventEmitter<DatabaseItem>;
@@ -70,6 +81,8 @@ export class ModelingEvents extends DisposableObject {
private readonly onModifiedMethodsChangedEventEmitter: AppEventEmitter<ModifiedMethodsChangedEvent>;
private readonly onSelectedMethodChangedEventEmitter: AppEventEmitter<SelectedMethodChangedEvent>;
private readonly onInProgressMethodsChangedEventEmitter: AppEventEmitter<InProgressMethodsChangedEvent>;
private readonly onRevealInModelEditorEventEmitter: AppEventEmitter<RevealInModelEditorEvent>;
private readonly onFocusModelEditorEventEmitter: AppEventEmitter<FocusModelEditorEvent>;
constructor(app: App) {
super();
@@ -126,6 +139,16 @@ export class ModelingEvents extends DisposableObject {
);
this.onInProgressMethodsChanged =
this.onInProgressMethodsChangedEventEmitter.event;
this.onRevealInModelEditorEventEmitter = this.push(
app.createEventEmitter<RevealInModelEditorEvent>(),
);
this.onRevealInModelEditor = this.onRevealInModelEditorEventEmitter.event;
this.onFocusModelEditorEventEmitter = this.push(
app.createEventEmitter<FocusModelEditorEvent>(),
);
this.onFocusModelEditor = this.onFocusModelEditorEventEmitter.event;
}
public fireActiveDbChangedEvent() {
@@ -220,4 +243,17 @@ export class ModelingEvents extends DisposableObject {
methods,
});
}
public fireRevealInModelEditorEvent(dbUri: string, method: Method) {
this.onRevealInModelEditorEventEmitter.fire({
dbUri,
method,
});
}
public fireFocusModelEditorEvent(dbUri: string) {
this.onFocusModelEditorEventEmitter.fire({
dbUri,
});
}
}

View File

@@ -112,6 +112,10 @@ export class ModelingStore extends DisposableObject {
return this.state.size > 0;
}
public isDbOpen(dbUri: string): boolean {
return this.state.has(dbUri);
}
/**
* Returns the method for the given database item and method signature.
* Returns undefined if no method exists with that signature.

View File

@@ -1,19 +0,0 @@
import { mockedObject } from "../../vscode-tests/utils/mocking.helpers";
import { ModelEditorViewTracker } from "../../../src/model-editor/model-editor-view-tracker";
import { ModelEditorView } from "../../../src/model-editor/model-editor-view";
export function createMockModelEditorViewTracker({
registerView = jest.fn(),
unregisterView = jest.fn(),
getView = jest.fn(),
}: {
registerView?: ModelEditorViewTracker["registerView"];
unregisterView?: ModelEditorViewTracker["unregisterView"];
getView?: ModelEditorViewTracker["getView"];
} = {}): ModelEditorViewTracker<ModelEditorView> {
return mockedObject<ModelEditorViewTracker<ModelEditorView>>({
registerView,
unregisterView,
getView,
});
}

View File

@@ -10,6 +10,8 @@ export function createMockModelingEvents({
onModeledMethodsChanged = jest.fn(),
onModifiedMethodsChanged = jest.fn(),
onInProgressMethodsChanged = jest.fn(),
onRevealInModelEditor = jest.fn(),
onFocusModelEditor = jest.fn(),
}: {
onActiveDbChanged?: ModelingEvents["onActiveDbChanged"];
onDbClosed?: ModelingEvents["onDbClosed"];
@@ -19,6 +21,8 @@ export function createMockModelingEvents({
onModeledMethodsChanged?: ModelingEvents["onModeledMethodsChanged"];
onModifiedMethodsChanged?: ModelingEvents["onModifiedMethodsChanged"];
onInProgressMethodsChanged?: ModelingEvents["onInProgressMethodsChanged"];
onRevealInModelEditor?: ModelingEvents["onRevealInModelEditor"];
onFocusModelEditor?: ModelingEvents["onFocusModelEditor"];
} = {}): ModelingEvents {
return mockedObject<ModelingEvents>({
onActiveDbChanged,
@@ -29,5 +33,7 @@ export function createMockModelingEvents({
onModeledMethodsChanged,
onModifiedMethodsChanged,
onInProgressMethodsChanged,
onRevealInModelEditor,
onFocusModelEditor,
});
}

View File

@@ -9,7 +9,6 @@ import { mockEmptyDatabaseManager } from "../query-testing/test-runner-helpers";
import { QueryRunner } from "../../../../src/query-server";
import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pack";
import { createMockModelingStore } from "../../../__mocks__/model-editor/modelingStoreMock";
import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock";
import { ModelConfigListener } from "../../../../src/config";
import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock";
import { QueryLanguage } from "../../../../src/common/query-language";
@@ -18,7 +17,6 @@ describe("ModelEditorView", () => {
const app = createMockApp({});
const modelingStore = createMockModelingStore();
const modelingEvents = createMockModelingEvents();
const viewTracker = createMockModelEditorViewTracker();
const modelConfig = mockedObject<ModelConfigListener>({
onDidChangeConfiguration: jest.fn(),
});
@@ -48,7 +46,6 @@ describe("ModelEditorView", () => {
app,
modelingStore,
modelingEvents,
viewTracker,
modelConfig,
databaseManager,
cliServer,