Merge pull request #2896 from github/koesie10/reveal-in-editor

Add reveal in editor button to method modeling panel
This commit is contained in:
Koen Vlaswinkel
2023-10-03 11:12:44 +02:00
committed by GitHub
21 changed files with 341 additions and 94 deletions

View File

@@ -575,12 +575,18 @@ interface SetModeledMethodMessage {
method: ModeledMethod;
}
interface RevealMethodMessage {
t: "revealMethod";
method: Method;
}
export type ToModelEditorMessage =
| SetExtensionPackStateMessage
| SetMethodsMessage
| SetModeledMethodsMessage
| SetModifiedMethodsMessage
| SetInProgressMethodsMessage;
| SetInProgressMethodsMessage
| RevealMethodMessage;
export type FromModelEditorMessage =
| ViewLoadedMsg
@@ -597,9 +603,15 @@ export type FromModelEditorMessage =
| HideModeledMethodsMessage
| SetModeledMethodMessage;
interface RevealInEditorMessage {
t: "revealInModelEditor";
method: Method;
}
export type FromMethodModelingMessage =
| CommonFromViewMessages
| SetModeledMethodMessage;
| SetModeledMethodMessage
| RevealInEditorMessage;
interface SetMethodMessage {
t: "setMethod";

View File

@@ -4,14 +4,23 @@ 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";
export class MethodModelingPanel extends DisposableObject {
private readonly provider: MethodModelingViewProvider;
constructor(app: App, modelingStore: ModelingStore) {
constructor(
app: App,
modelingStore: ModelingStore,
editorViewTracker: ModelEditorViewTracker,
) {
super();
this.provider = new MethodModelingViewProvider(app, modelingStore);
this.provider = new MethodModelingViewProvider(
app,
modelingStore,
editorViewTracker,
);
this.push(
window.registerWebviewViewProvider(
MethodModelingViewProvider.viewType,

View File

@@ -8,8 +8,10 @@ import { extLogger } from "../../common/logging/vscode/loggers";
import { App } from "../../common/app";
import { redactableError } from "../../common/errors";
import { Method } from "../method";
import { ModelingStore } from "../modeling-store";
import { DbModelingState, 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";
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
ToMethodModelingMessage,
@@ -22,6 +24,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
constructor(
app: App,
private readonly modelingStore: ModelingStore,
private readonly editorViewTracker: ModelEditorViewTracker,
) {
super(app, "method-modeling");
}
@@ -77,19 +80,45 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
break;
case "setModeledMethod": {
const activeState = this.modelingStore.getStateForActiveDb();
if (!activeState) {
throw new Error("No active state found in modeling store");
}
const activeState = this.ensureActiveState();
this.modelingStore.updateModeledMethod(
activeState.databaseItem,
msg.method,
);
break;
}
case "revealInModelEditor":
await this.revealInModelEditor(msg.method);
break;
default:
assertNever(msg);
}
}
private async revealInModelEditor(method: Method): Promise<void> {
const activeState = this.ensureActiveState();
const views = this.editorViewTracker.getViews(
activeState.databaseItem.databaseUri.toString(),
);
if (views.length === 0) {
return;
}
await Promise.all(views.map((view) => view.revealMethod(method)));
}
private ensureActiveState(): DbModelingState {
const activeState = this.modelingStore.getStateForActiveDb();
if (!activeState) {
throw new Error("No active state found in modeling store");
}
return activeState;
}
private registerToModelingStoreEvents(): void {
this.push(
this.modelingStore.onModeledMethodsChanged(async (e) => {

View File

@@ -20,12 +20,14 @@ import { setUpPack } from "./model-editor-queries";
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";
const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
export class ModelEditorModule extends DisposableObject {
private readonly queryStorageDir: string;
private readonly modelingStore: ModelingStore;
private readonly editorViewTracker: ModelEditorViewTracker<ModelEditorView>;
private readonly methodsUsagePanel: MethodsUsagePanel;
private readonly methodModelingPanel: MethodModelingPanel;
@@ -39,11 +41,12 @@ export class ModelEditorModule extends DisposableObject {
super();
this.queryStorageDir = join(baseQueryStorageDir, "model-editor-results");
this.modelingStore = new ModelingStore(app);
this.editorViewTracker = new ModelEditorViewTracker();
this.methodsUsagePanel = this.push(
new MethodsUsagePanel(this.modelingStore, cliServer),
);
this.methodModelingPanel = this.push(
new MethodModelingPanel(app, this.modelingStore),
new MethodModelingPanel(app, this.modelingStore, this.editorViewTracker),
);
this.registerToModelingStoreEvents();
@@ -148,6 +151,7 @@ export class ModelEditorModule extends DisposableObject {
const view = new ModelEditorView(
this.app,
this.modelingStore,
this.editorViewTracker,
this.databaseManager,
this.cliServer,
this.queryRunner,

View File

@@ -0,0 +1,41 @@
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)) {
this.views.set(databaseUri, []);
}
this.views.get(databaseUri)?.push(view);
}
public unregisterView(view: T): void {
const views = this.views.get(view.databaseUri);
if (!views) {
return;
}
const index = views.indexOf(view);
if (index !== -1) {
views.splice(index, 1);
}
}
public getViews(databaseUri: string): T[] {
return this.views.get(databaseUri) ?? [];
}
}

View File

@@ -42,6 +42,7 @@ import { getLanguageDisplayName } from "../common/query-language";
import { AutoModeler } from "./auto-modeler";
import { telemetryListener } from "../common/vscode/telemetry";
import { ModelingStore } from "./modeling-store";
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
export class ModelEditorView extends AbstractWebview<
ToModelEditorMessage,
@@ -52,6 +53,7 @@ export class ModelEditorView extends AbstractWebview<
public constructor(
protected readonly app: App,
private readonly modelingStore: ModelingStore,
private readonly viewTracker: ModelEditorViewTracker<ModelEditorView>,
private readonly databaseManager: DatabaseManager,
private readonly cliServer: CodeQLCliServer,
private readonly queryRunner: QueryRunner,
@@ -66,6 +68,8 @@ export class ModelEditorView extends AbstractWebview<
this.modelingStore.initializeStateForDb(databaseItem);
this.registerToModelingStoreEvents();
this.viewTracker.registerView(this);
this.autoModeler = new AutoModeler(
app,
cliServer,
@@ -181,7 +185,7 @@ export class ModelEditorView extends AbstractWebview<
}
protected onPanelDispose(): void {
// Nothing to do here
this.viewTracker.unregisterView(this);
}
protected async onMessage(msg: FromModelEditorMessage): Promise<void> {
@@ -338,6 +342,19 @@ export class ModelEditorView extends AbstractWebview<
]);
}
public get databaseUri(): string {
return this.databaseItem.databaseUri.toString();
}
public async revealMethod(method: Method): Promise<void> {
this.panel?.reveal();
await this.postMessage({
t: "revealMethod",
method,
});
}
private async setViewState(): Promise<void> {
const showLlmButton =
this.databaseItem.language === "java" && showLlmGeneration();
@@ -497,6 +514,7 @@ export class ModelEditorView extends AbstractWebview<
const view = new ModelEditorView(
this.app,
this.modelingStore,
this.viewTracker,
this.databaseManager,
this.cliServer,
this.queryRunner,

View File

@@ -6,7 +6,7 @@ import { Method, Usage } from "./method";
import { ModeledMethod } from "./modeled-method";
import { INITIAL_HIDE_MODELED_METHODS_VALUE } from "./shared/hide-modeled-methods";
interface DbModelingState {
export interface DbModelingState {
databaseItem: DatabaseItem;
methods: Method[];
hideModeledMethods: boolean;

View File

@@ -7,6 +7,7 @@ import { MethodName } from "../model-editor/MethodName";
import { ModeledMethod } from "../../model-editor/modeled-method";
import { MethodModelingInputs } from "./MethodModelingInputs";
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
import { ReviewInEditorButton } from "./ReviewInEditorButton";
const Container = styled.div`
padding: 0.3rem;
@@ -64,6 +65,7 @@ export const MethodModeling = ({
modeledMethod={modeledMethod}
onChange={onChange}
/>
<ReviewInEditorButton method={method} />
</Container>
);
};

View File

@@ -0,0 +1,25 @@
import * as React from "react";
import { useCallback } from "react";
import { styled } from "styled-components";
import { vscode } from "../vscode-api";
import TextButton from "../common/TextButton";
import { Method } from "../../model-editor/method";
const Button = styled(TextButton)`
margin-top: 0.5rem;
`;
type Props = {
method: Method;
};
export const ReviewInEditorButton = ({ method }: Props) => {
const handleClick = useCallback(() => {
vscode.postMessage({
t: "revealInModelEditor",
method,
});
}, [method]);
return <Button onClick={handleClick}>Review in editor</Button>;
};

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { styled } from "styled-components";
import { Method } from "../../model-editor/method";
import { ModeledMethod } from "../../model-editor/modeled-method";
@@ -76,6 +76,7 @@ export type LibraryRowProps = {
inProgressMethods: InProgressMethods;
viewState: ModelEditorViewState;
hideModeledMethods: boolean;
revealedMethodSignature: string | null;
onChange: (modeledMethod: ModeledMethod) => void;
onSaveModelClick: (
methods: Method[],
@@ -100,6 +101,7 @@ export const LibraryRow = ({
inProgressMethods,
viewState,
hideModeledMethods,
revealedMethodSignature,
onChange,
onSaveModelClick,
onGenerateFromLlmClick,
@@ -117,6 +119,14 @@ export const LibraryRow = ({
setExpanded((oldIsExpanded) => !oldIsExpanded);
}, []);
useEffect(() => {
// If any of the methods in this group is the one that should be revealed, we should expand
// this group so the method can highlight itself.
if (methods.some((m) => m.signature === revealedMethodSignature)) {
setExpanded(true);
}
}, [methods, revealedMethodSignature]);
const handleModelWithAI = useCallback(
async (e: React.MouseEvent) => {
onGenerateFromLlmClick(title, methods, modeledMethods);
@@ -227,6 +237,7 @@ export const LibraryRow = ({
inProgressMethods={inProgressMethods}
mode={viewState.mode}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}
onChange={onChange}
/>
<SectionDivider />

View File

@@ -5,7 +5,7 @@ import {
VSCodeProgressRing,
} from "@vscode/webview-ui-toolkit/react";
import * as React from "react";
import { useCallback } from "react";
import { forwardRef, useCallback, useEffect, useRef } from "react";
import { styled } from "styled-components";
import { vscode } from "../vscode-api";
@@ -47,6 +47,11 @@ const ProgressRing = styled(VSCodeProgressRing)`
margin-left: auto;
`;
const DataGridRow = styled(VSCodeDataGridRow)<{ focused?: boolean }>`
outline: ${(props) =>
props.focused ? "1px solid var(--vscode-focusBorder)" : "none"};
`;
export type MethodRowProps = {
method: Method;
methodCanBeModeled: boolean;
@@ -54,97 +59,126 @@ export type MethodRowProps = {
methodIsUnsaved: boolean;
modelingInProgress: boolean;
mode: Mode;
revealedMethodSignature: string | null;
onChange: (modeledMethod: ModeledMethod) => void;
};
export const MethodRow = (props: MethodRowProps) => {
const { methodCanBeModeled } = props;
const { method, methodCanBeModeled, revealedMethodSignature } = props;
const ref = useRef<HTMLElement>();
useEffect(() => {
if (method.signature === revealedMethodSignature) {
ref.current?.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
}, [method, revealedMethodSignature]);
if (methodCanBeModeled) {
return <ModelableMethodRow {...props} />;
return <ModelableMethodRow {...props} ref={ref} />;
} else {
return <UnmodelableMethodRow {...props} />;
return <UnmodelableMethodRow {...props} ref={ref} />;
}
};
function ModelableMethodRow(props: MethodRowProps) {
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;
const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
(props, ref) => {
const {
method,
modeledMethod,
methodIsUnsaved,
mode,
revealedMethodSignature,
onChange,
} = props;
const jumpToUsage = useCallback(
() => sendJumpToUsageMessage(method),
[method],
);
const jumpToUsage = useCallback(
() => sendJumpToUsageMessage(method),
[method],
);
const modelingStatus = getModelingStatus(modeledMethod, methodIsUnsaved);
const modelingStatus = getModelingStatus(modeledMethod, methodIsUnsaved);
return (
<VSCodeDataGridRow data-testid="modelable-method-row">
<ApiOrMethodCell gridColumn={1}>
<ModelingStatusIndicator status={modelingStatus} />
<MethodClassifications method={method} />
<MethodName {...props.method} />
{mode === Mode.Application && (
<UsagesButton onClick={jumpToUsage}>
{method.usages.length}
</UsagesButton>
return (
<DataGridRow
data-testid="modelable-method-row"
ref={ref}
focused={revealedMethodSignature === method.signature}
>
<ApiOrMethodCell gridColumn={1}>
<ModelingStatusIndicator status={modelingStatus} />
<MethodClassifications method={method} />
<MethodName {...props.method} />
{mode === Mode.Application && (
<UsagesButton onClick={jumpToUsage}>
{method.usages.length}
</UsagesButton>
)}
<ViewLink onClick={jumpToUsage}>View</ViewLink>
{props.modelingInProgress && <ProgressRing />}
</ApiOrMethodCell>
{props.modelingInProgress && (
<>
<VSCodeDataGridCell gridColumn={2}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
<InProgressDropdown />
</VSCodeDataGridCell>
</>
)}
<ViewLink onClick={jumpToUsage}>View</ViewLink>
{props.modelingInProgress && <ProgressRing />}
</ApiOrMethodCell>
{props.modelingInProgress && (
<>
<VSCodeDataGridCell gridColumn={2}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<InProgressDropdown />
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
<InProgressDropdown />
</VSCodeDataGridCell>
</>
)}
{!props.modelingInProgress && (
<>
<VSCodeDataGridCell gridColumn={2}>
<ModelTypeDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
<ModelInputDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<ModelOutputDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
<ModelKindDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
</>
)}
</VSCodeDataGridRow>
);
}
{!props.modelingInProgress && (
<>
<VSCodeDataGridCell gridColumn={2}>
<ModelTypeDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
<ModelInputDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<ModelOutputDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
<ModelKindDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
</>
)}
</DataGridRow>
);
},
);
ModelableMethodRow.displayName = "ModelableMethodRow";
function UnmodelableMethodRow(props: MethodRowProps) {
const { method, mode } = props;
const UnmodelableMethodRow = forwardRef<
HTMLElement | undefined,
MethodRowProps
>((props, ref) => {
const { method, mode, revealedMethodSignature } = props;
const jumpToUsage = useCallback(
() => sendJumpToUsageMessage(method),
@@ -152,7 +186,11 @@ function UnmodelableMethodRow(props: MethodRowProps) {
);
return (
<VSCodeDataGridRow data-testid="unmodelable-method-row">
<DataGridRow
data-testid="unmodelable-method-row"
ref={ref}
focused={revealedMethodSignature === method.signature}
>
<ApiOrMethodCell gridColumn={1}>
<ModelingStatusIndicator status="saved" />
<MethodName {...props.method} />
@@ -167,9 +205,10 @@ function UnmodelableMethodRow(props: MethodRowProps) {
<VSCodeDataGridCell gridColumn="span 4">
Method already modeled
</VSCodeDataGridCell>
</VSCodeDataGridRow>
</DataGridRow>
);
}
});
UnmodelableMethodRow.displayName = "UnmodelableMethodRow";
function sendJumpToUsageMessage(method: Method) {
vscode.postMessage({

View File

@@ -101,6 +101,10 @@ export function ModelEditor({
initialHideModeledMethods,
);
const [revealedMethodSignature, setRevealedMethodSignature] = useState<
string | null
>(null);
useEffect(() => {
vscode.postMessage({
t: "hideModeledMethods",
@@ -136,6 +140,10 @@ export function ModelEditor({
new Set(msg.inProgressMethods),
),
);
break;
case "revealMethod":
setRevealedMethodSignature(msg.method.signature);
break;
default:
assertNever(msg);
@@ -153,6 +161,20 @@ export function ModelEditor({
};
}, []);
useEffect(() => {
// If there is a revealed method signature, hide it when the user clicks anywhere. In this case, we do need to
// show the user where the method is anymore and they should have seen it.
const listener = () => {
setRevealedMethodSignature(null);
};
window.addEventListener("click", listener);
return () => {
window.removeEventListener("click", listener);
};
}, []);
const modeledPercentage = useMemo(
() => calculateModeledPercentage(methods),
[methods],
@@ -323,6 +345,7 @@ export function ModelEditor({
inProgressMethods={inProgressMethods}
viewState={viewState}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}
onChange={onChange}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}

View File

@@ -23,6 +23,7 @@ export type ModeledMethodDataGridProps = {
inProgressMethods: InProgressMethods;
mode: Mode;
hideModeledMethods: boolean;
revealedMethodSignature: string | null;
onChange: (modeledMethod: ModeledMethod) => void;
};
@@ -34,6 +35,7 @@ export const ModeledMethodDataGrid = ({
inProgressMethods,
mode,
hideModeledMethods,
revealedMethodSignature,
onChange,
}: ModeledMethodDataGridProps) => {
const [methodsWithModelability, numHiddenMethods]: [
@@ -94,6 +96,7 @@ export const ModeledMethodDataGrid = ({
method.signature,
)}
mode={mode}
revealedMethodSignature={revealedMethodSignature}
onChange={onChange}
/>
))}

View File

@@ -16,6 +16,7 @@ export type ModeledMethodsListProps = {
modeledMethods: Record<string, ModeledMethod>;
modifiedSignatures: Set<string>;
inProgressMethods: InProgressMethods;
revealedMethodSignature: string | null;
viewState: ModelEditorViewState;
hideModeledMethods: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
@@ -44,6 +45,7 @@ export const ModeledMethodsList = ({
inProgressMethods,
viewState,
hideModeledMethods,
revealedMethodSignature,
onChange,
onSaveModelClick,
onGenerateFromLlmClick,
@@ -89,6 +91,7 @@ export const ModeledMethodsList = ({
inProgressMethods={inProgressMethods}
viewState={viewState}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}
onChange={onChange}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}

View File

@@ -43,6 +43,7 @@ describe(LibraryRow.name, () => {
inProgressMethods={new InProgressMethods()}
viewState={viewState}
hideModeledMethods={false}
revealedMethodSignature={null}
onChange={onChange}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}

View File

@@ -39,6 +39,7 @@ describe(MethodRow.name, () => {
modeledMethod={modeledMethod}
methodIsUnsaved={false}
modelingInProgress={false}
revealedMethodSignature={null}
mode={Mode.Application}
onChange={onChange}
{...props}

View File

@@ -60,6 +60,7 @@ describe(ModeledMethodDataGrid.name, () => {
inProgressMethods={new InProgressMethods()}
mode={Mode.Application}
hideModeledMethods={false}
revealedMethodSignature={null}
onChange={onChange}
{...props}
/>,

View File

@@ -69,6 +69,7 @@ describe(ModeledMethodsList.name, () => {
inProgressMethods={new InProgressMethods()}
viewState={viewState}
hideModeledMethods={false}
revealedMethodSignature={null}
onChange={onChange}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}

View File

@@ -1,5 +1,6 @@
import {
FromCompareViewMessage,
FromMethodModelingMessage,
FromModelEditorMessage,
FromResultsViewMsg,
FromVariantAnalysisMessage,
@@ -15,7 +16,8 @@ export interface VsCodeApi {
| FromResultsViewMsg
| FromCompareViewMessage
| FromVariantAnalysisMessage
| FromModelEditorMessage,
| FromModelEditorMessage
| FromMethodModelingMessage,
): void;
/**

View File

@@ -0,0 +1,19 @@
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(),
getViews = jest.fn(),
}: {
registerView?: ModelEditorViewTracker["registerView"];
unregisterView?: ModelEditorViewTracker["unregisterView"];
getViews?: ModelEditorViewTracker["getViews"];
} = {}): ModelEditorViewTracker<ModelEditorView> {
return mockedObject<ModelEditorViewTracker<ModelEditorView>>({
registerView,
unregisterView,
getViews,
});
}

View File

@@ -9,10 +9,12 @@ 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";
describe("ModelEditorView", () => {
const app = createMockApp({});
const modelingStore = createMockModelingStore();
const viewTracker = createMockModelEditorViewTracker();
const databaseManager = mockEmptyDatabaseManager();
const cliServer = mockedObject<CodeQLCliServer>({});
const queryRunner = mockedObject<QueryRunner>({});
@@ -38,6 +40,7 @@ describe("ModelEditorView", () => {
view = new ModelEditorView(
app,
modelingStore,
viewTracker,
databaseManager,
cliServer,
queryRunner,