Merge pull request #3399 from github/koesie10/hide-type-models-non-canary

Hide type models for Ruby by default
This commit is contained in:
Koen Vlaswinkel
2024-02-26 11:58:30 +01:00
committed by GitHub
18 changed files with 157 additions and 9 deletions

View File

@@ -724,6 +724,7 @@ export async function setAutogenerateQlPacks(choice: AutogenerateQLPacks) {
const MODEL_SETTING = new Setting("model", ROOT_SETTING);
const FLOW_GENERATION = new Setting("flowGeneration", MODEL_SETTING);
const LLM_GENERATION = new Setting("llmGeneration", MODEL_SETTING);
const SHOW_TYPE_MODELS = new Setting("showTypeModels", MODEL_SETTING);
const LLM_GENERATION_BATCH_SIZE = new Setting(
"llmGenerationBatchSize",
MODEL_SETTING,
@@ -743,6 +744,7 @@ const ENABLE_ACCESS_PATH_SUGGESTIONS = new Setting(
export interface ModelConfig {
flowGeneration: boolean;
llmGeneration: boolean;
showTypeModels: boolean;
getExtensionsDirectory(languageId: string): string | undefined;
enablePython: boolean;
enableAccessPathSuggestions: boolean;
@@ -761,6 +763,10 @@ export class ModelConfigListener extends ConfigListener implements ModelConfig {
return !!LLM_GENERATION.getValue<boolean>();
}
public get showTypeModels(): boolean {
return !!SHOW_TYPE_MODELS.getValue<boolean>();
}
/**
* Limits the number of candidates we send to the model in each request to avoid long requests.
* Note that the model may return fewer than this number of candidates.

View File

@@ -17,9 +17,37 @@ import type {
import type { BaseLogger } from "../../common/logging";
import type { AccessPathSuggestionRow } from "../suggestions";
// This is a subset of the model config that doesn't import the vscode module.
// It only includes settings that are actually used.
export type ModelConfig = {
showTypeModels: boolean;
};
/**
* This function creates a new model config object from the given model config object.
* The new model config object is a deep copy of the given model config object.
*
* @param modelConfig The model config object to create a new model config object from.
* In most cases, this is a `ModelConfigListener`.
*/
export function createModelConfig(modelConfig: ModelConfig): ModelConfig {
return {
showTypeModels: modelConfig.showTypeModels,
};
}
export const defaultModelConfig: ModelConfig = {
showTypeModels: false,
};
type GenerateMethodDefinition<T> = (method: T) => DataTuple[];
type ReadModeledMethod = (row: DataTuple[]) => ModeledMethod;
type IsHiddenContext = {
method: MethodDefinition;
config: ModelConfig;
};
export type ModelsAsDataLanguagePredicate<T> = {
extensiblePredicate: string;
supportedKinds?: string[];
@@ -30,6 +58,14 @@ export type ModelsAsDataLanguagePredicate<T> = {
supportedEndpointTypes?: EndpointType[];
generateMethodDefinition: GenerateMethodDefinition<T>;
readModeledMethod: ReadModeledMethod;
/**
* Controls whether this predicate is hidden for a certain method. This only applies to the UI.
* If not specified, the predicate is visible for all methods.
*
* @param method The method to check if the predicate is hidden for.
*/
isHidden?: (context: IsHiddenContext) => boolean;
};
type ParseGenerationResults = (

View File

@@ -169,6 +169,7 @@ export const ruby: ModelsAsDataLanguage = {
methodParameters: "",
};
},
isHidden: ({ config }) => !config.showTypeModels,
},
},
modelGeneration: {

View File

@@ -15,6 +15,7 @@ import type { DatabaseItem } from "../../databases/local-databases";
import type { ModelingEvents } from "../modeling-events";
import type { QueryLanguage } from "../../common/query-language";
import { tryGetQueryLanguage } from "../../common/query-language";
import { createModelConfig } from "../languages";
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
ToMethodModelingMessage,
@@ -46,6 +47,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
t: "setMethodModelingPanelViewState",
viewState: {
language: this.language,
modelConfig: createModelConfig(this.modelConfig),
},
});
}

View File

@@ -50,7 +50,7 @@ import { telemetryListener } from "../common/vscode/telemetry";
import type { ModelingStore } from "./modeling-store";
import type { ModelingEvents } from "./modeling-events";
import type { ModelsAsDataLanguage } from "./languages";
import { getModelsAsDataLanguage } from "./languages";
import { createModelConfig, getModelsAsDataLanguage } from "./languages";
import { runGenerateQueries } from "./generate";
import { ResponseError } from "vscode-jsonrpc";
import { LSPErrorCodes } from "vscode-languageclient";
@@ -456,6 +456,7 @@ export class ModelEditorView extends AbstractWebview<
mode: this.modelingStore.getMode(this.databaseItem),
showModeSwitchButton,
sourceArchiveAvailable,
modelConfig: createModelConfig(this.modelConfig),
},
});
}

View File

@@ -1,6 +1,7 @@
import type { ExtensionPack } from "./extension-pack";
import type { Mode } from "./mode";
import type { QueryLanguage } from "../../common/query-language";
import type { ModelConfig } from "../languages";
export interface ModelEditorViewState {
extensionPack: ExtensionPack;
@@ -11,8 +12,10 @@ export interface ModelEditorViewState {
mode: Mode;
showModeSwitchButton: boolean;
sourceArchiveAvailable: boolean;
modelConfig: ModelConfig;
}
export interface MethodModelingPanelViewState {
language: QueryLanguage | undefined;
modelConfig: ModelConfig;
}

View File

@@ -6,6 +6,7 @@ import { createSinkModeledMethod } from "../../../test/factories/model-editor/mo
import { useState } from "react";
import type { ModeledMethod } from "../../model-editor/modeled-method";
import { QueryLanguage } from "../../common/query-language";
import { defaultModelConfig } from "../../model-editor/languages";
export default {
title: "Method Modeling/Method Modeling Inputs",
@@ -34,6 +35,7 @@ const Template: StoryFn<typeof MethodModelingInputsComponent> = (args) => {
language={QueryLanguage.Java}
modeledMethod={m}
onChange={onChange}
modelConfig={defaultModelConfig}
/>
);
};

View File

@@ -8,6 +8,7 @@ import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
import { ReviewInEditorButton } from "./ReviewInEditorButton";
import { MultipleModeledMethodsPanel } from "./MultipleModeledMethodsPanel";
import type { QueryLanguage } from "../../common/query-language";
import type { ModelConfig } from "../../model-editor/languages";
const Container = styled.div`
padding-top: 0.5rem;
@@ -50,6 +51,7 @@ const UnsavedTag = ({ modelingStatus }: { modelingStatus: ModelingStatus }) => (
export type MethodModelingProps = {
language: QueryLanguage;
modelConfig: ModelConfig;
modelingStatus: ModelingStatus;
method: Method;
modeledMethods: ModeledMethod[];
@@ -60,6 +62,7 @@ export type MethodModelingProps = {
export const MethodModeling = ({
language,
modelConfig,
modelingStatus,
modeledMethods,
method,
@@ -80,6 +83,7 @@ export const MethodModeling = ({
</DependencyContainer>
<MultipleModeledMethodsPanel
language={language}
modelConfig={modelConfig}
method={method}
modeledMethods={modeledMethods}
isModelingInProgress={isModelingInProgress}

View File

@@ -7,6 +7,7 @@ import { ModelOutputDropdown } from "../model-editor/ModelOutputDropdown";
import { ModelKindDropdown } from "../model-editor/ModelKindDropdown";
import { InProgressDropdown } from "../model-editor/InProgressDropdown";
import type { QueryLanguage } from "../../common/query-language";
import type { ModelConfig } from "../../model-editor/languages";
const Container = styled.div`
padding-top: 0.5rem;
@@ -24,6 +25,7 @@ const Name = styled.span`
export type MethodModelingInputsProps = {
language: QueryLanguage;
modelConfig: ModelConfig;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
@@ -33,6 +35,7 @@ export type MethodModelingInputsProps = {
export const MethodModelingInputs = ({
language,
modelConfig,
method,
modeledMethod,
modelPending,
@@ -55,7 +58,7 @@ export const MethodModelingInputs = ({
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelTypeDropdown {...inputProps} />
<ModelTypeDropdown modelConfig={modelConfig} {...inputProps} />
)}
</Input>
</Container>

View File

@@ -11,6 +11,7 @@ import { NotInModelingMode } from "./NotInModelingMode";
import { NoMethodSelected } from "./NoMethodSelected";
import type { MethodModelingPanelViewState } from "../../model-editor/shared/view-state";
import { MethodAlreadyModeled } from "./MethodAlreadyModeled";
import { defaultModelConfig } from "../../model-editor/languages";
type Props = {
initialViewState?: MethodModelingPanelViewState;
@@ -116,6 +117,7 @@ export function MethodModelingView({
return (
<MethodModeling
language={viewState?.language}
modelConfig={viewState?.modelConfig ?? defaultModelConfig}
modelingStatus={modelingStatus}
method={method}
modeledMethods={modeledMethods}

View File

@@ -16,9 +16,11 @@ import type { QueryLanguage } from "../../common/query-language";
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
import { sendTelemetry } from "../common/telemetry";
import type { ModelingStatus } from "../../model-editor/shared/modeling-status";
import type { ModelConfig } from "../../model-editor/languages";
export type MultipleModeledMethodsPanelProps = {
language: QueryLanguage;
modelConfig: ModelConfig;
method: Method;
modeledMethods: ModeledMethod[];
modelingStatus: ModelingStatus;
@@ -61,6 +63,7 @@ const ModificationActions = styled.div`
export const MultipleModeledMethodsPanel = ({
language,
modelConfig,
method,
modeledMethods,
modelingStatus,
@@ -157,6 +160,7 @@ export const MultipleModeledMethodsPanel = ({
{modeledMethods.length > 0 ? (
<MethodModelingInputs
language={language}
modelConfig={modelConfig}
method={method}
modeledMethod={modeledMethods[selectedIndex]}
modelPending={isModelPending(
@@ -170,6 +174,7 @@ export const MultipleModeledMethodsPanel = ({
) : (
<MethodModelingInputs
language={language}
modelConfig={modelConfig}
method={method}
modeledMethod={undefined}
modelPending={isModelPending(

View File

@@ -4,6 +4,7 @@ import { MethodModeling } from "../MethodModeling";
import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { createSinkModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories";
import { QueryLanguage } from "../../../common/query-language";
import { defaultModelConfig } from "../../../model-editor/languages";
describe(MethodModeling.name, () => {
const render = (props: MethodModelingProps) =>
@@ -18,6 +19,7 @@ describe(MethodModeling.name, () => {
render({
language: QueryLanguage.Java,
modelConfig: defaultModelConfig,
modelingStatus: "saved",
method,
modeledMethods: [modeledMethod],

View File

@@ -9,6 +9,7 @@ import {
} from "../../../../test/factories/model-editor/modeled-method-factories";
import { QueryLanguage } from "../../../common/query-language";
import { createEmptyModeledMethod } from "../../../model-editor/modeled-method-empty";
import { defaultModelConfig } from "../../../model-editor/languages";
describe(MethodModelingInputs.name, () => {
const render = (props: MethodModelingInputsProps) =>
@@ -19,6 +20,7 @@ describe(MethodModelingInputs.name, () => {
const modeledMethod = createSinkModeledMethod();
const modelPending = false;
const isModelingInProgress = false;
const modelConfig = defaultModelConfig;
const onChange = jest.fn();
it("renders the method modeling inputs", () => {
@@ -28,6 +30,7 @@ describe(MethodModelingInputs.name, () => {
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@@ -55,6 +58,7 @@ describe(MethodModelingInputs.name, () => {
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@@ -78,6 +82,7 @@ describe(MethodModelingInputs.name, () => {
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@@ -93,6 +98,7 @@ describe(MethodModelingInputs.name, () => {
modeledMethod={updatedModeledMethod}
modelPending={modelPending}
isModelingInProgress={isModelingInProgress}
modelConfig={modelConfig}
onChange={onChange}
/>,
);
@@ -123,6 +129,7 @@ describe(MethodModelingInputs.name, () => {
modeledMethod,
modelPending,
isModelingInProgress: true,
modelConfig,
onChange,
});

View File

@@ -11,6 +11,7 @@ import { userEvent } from "@testing-library/user-event";
import type { ModeledMethod } from "../../../model-editor/modeled-method";
import { QueryLanguage } from "../../../common/query-language";
import type { ModelingStatus } from "../../../model-editor/shared/modeling-status";
import { defaultModelConfig } from "../../../model-editor/languages";
describe(MultipleModeledMethodsPanel.name, () => {
const language = QueryLanguage.Java;
@@ -19,12 +20,14 @@ describe(MultipleModeledMethodsPanel.name, () => {
const isProcessedByAutoModel = false;
const modelingStatus: ModelingStatus = "unmodeled";
const onChange = jest.fn<void, [string, ModeledMethod[]]>();
const modelConfig = defaultModelConfig;
const baseProps = {
language,
method,
modelingStatus,
isModelingInProgress,
modelConfig,
isProcessedByAutoModel,
onChange,
};

View File

@@ -37,6 +37,7 @@ import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empt
import type { AccessPathOption } from "../../model-editor/suggestions";
import { ModelInputSuggestBox } from "./ModelInputSuggestBox";
import { ModelOutputSuggestBox } from "./ModelOutputSuggestBox";
import { getModelsAsDataLanguage } from "../../model-editor/languages";
const ApiOrMethodRow = styled.div`
min-height: calc(var(--input-height) * 1px);
@@ -192,9 +193,37 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
[method],
);
const modelingStatus = getModelingStatus(modeledMethods, methodIsUnsaved);
// Only show modeled methods that are non-hidden. These are also the ones that are
// used for determining the modeling status.
const shownModeledMethods = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(viewState.language);
const addModelButtonDisabled = !canAddNewModeledMethod(modeledMethods);
return modeledMethodsToDisplay(
modeledMethods.filter((modeledMethod) => {
if (modeledMethod.type === "none") {
return true;
}
const predicate = modelsAsDataLanguage.predicates[modeledMethod.type];
if (!predicate) {
return true;
}
return !predicate.isHidden?.({
method,
config: viewState.modelConfig,
});
}),
method,
);
}, [method, modeledMethods, viewState]);
const modelingStatus = getModelingStatus(
shownModeledMethods,
methodIsUnsaved,
);
const addModelButtonDisabled = !canAddNewModeledMethod(shownModeledMethods);
return (
<DataGridRow
@@ -206,7 +235,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
}}
>
<DataGridCell
gridRow={`span ${modeledMethods.length + validationErrors.length}`}
gridRow={`span ${shownModeledMethods.length + validationErrors.length}`}
ref={ref}
>
<ApiOrMethodRow>
@@ -257,7 +286,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
)}
{!props.modelingInProgress && (
<>
{modeledMethods.map((modeledMethod, index) => {
{shownModeledMethods.map((modeledMethod, index) => {
const modelPending = isModelPending(
modeledMethod,
modelingStatus,
@@ -269,6 +298,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
<DataGridCell>
<ModelTypeDropdown
language={viewState.language}
modelConfig={viewState.modelConfig}
method={method}
modeledMethod={modeledMethod}
modelPending={modelPending}

View File

@@ -10,12 +10,16 @@ import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empt
import type { Mutable } from "../../common/mutable";
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
import type { QueryLanguage } from "../../common/query-language";
import type { ModelsAsDataLanguagePredicates } from "../../model-editor/languages";
import type {
ModelConfig,
ModelsAsDataLanguagePredicates,
} from "../../model-editor/languages";
import { getModelsAsDataLanguage } from "../../model-editor/languages";
import { InputDropdown } from "./InputDropdown";
type Props = {
language: QueryLanguage;
modelConfig: ModelConfig;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
@@ -34,6 +38,7 @@ type Option = { value: ModeledMethodType; label: string };
export const ModelTypeDropdown = ({
language,
modelConfig,
method,
modeledMethod,
modelPending,
@@ -55,6 +60,13 @@ export const ModelTypeDropdown = ({
return null;
}
if (
predicate.isHidden &&
predicate.isHidden({ method, config: modelConfig })
) {
return null;
}
return {
value: type,
label: typeLabels[type],
@@ -64,7 +76,7 @@ export const ModelTypeDropdown = ({
];
return baseOptions;
}, [language, method.endpointType]);
}, [language, modelConfig, method]);
const handleChange = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {

View File

@@ -4,6 +4,7 @@ import { createNoneModeledMethod } from "../../../../test/factories/model-editor
import { QueryLanguage } from "../../../common/query-language";
import { ModelTypeDropdown } from "../ModelTypeDropdown";
import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { defaultModelConfig } from "../../../model-editor/languages";
describe(ModelTypeDropdown.name, () => {
const onChange = jest.fn();
@@ -23,6 +24,7 @@ describe(ModelTypeDropdown.name, () => {
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}
/>,
);
@@ -34,7 +36,7 @@ describe(ModelTypeDropdown.name, () => {
);
});
it("allows changing the type to 'Type' for Ruby", async () => {
it("allows changing the type to 'Type' for Ruby when type models are shown", async () => {
const method = createMethod();
const modeledMethod = createNoneModeledMethod();
@@ -45,6 +47,10 @@ describe(ModelTypeDropdown.name, () => {
modelPending={false}
onChange={onChange}
method={method}
modelConfig={{
...defaultModelConfig,
showTypeModels: true,
}}
/>,
);
@@ -56,6 +62,26 @@ describe(ModelTypeDropdown.name, () => {
);
});
it("does not allow changing the type to 'Type' for Ruby when type models are not shown", async () => {
const method = createMethod();
const modeledMethod = createNoneModeledMethod();
render(
<ModelTypeDropdown
language={QueryLanguage.Ruby}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}
/>,
);
expect(
screen.queryByRole("option", { name: "Type" }),
).not.toBeInTheDocument();
});
it("does not allow changing the type to 'Type' for Java", async () => {
const method = createMethod();
const modeledMethod = createNoneModeledMethod();
@@ -67,6 +93,7 @@ describe(ModelTypeDropdown.name, () => {
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}
/>,
);

View File

@@ -2,6 +2,7 @@ import type { ModelEditorViewState } from "../../../src/model-editor/shared/view
import { Mode } from "../../../src/model-editor/shared/mode";
import { createMockExtensionPack } from "./extension-pack";
import { QueryLanguage } from "../../../src/common/query-language";
import { defaultModelConfig } from "../../../src/model-editor/languages";
export function createMockModelEditorViewState(
data: Partial<ModelEditorViewState> = {},
@@ -15,6 +16,7 @@ export function createMockModelEditorViewState(
showModeSwitchButton: true,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
modelConfig: defaultModelConfig,
...data,
};
}