diff --git a/extensions/ql-vscode/src/view/model-editor/MethodRow.tsx b/extensions/ql-vscode/src/view/model-editor/MethodRow.tsx index e54e52d48..4b3b9e0df 100644 --- a/extensions/ql-vscode/src/view/model-editor/MethodRow.tsx +++ b/extensions/ql-vscode/src/view/model-editor/MethodRow.tsx @@ -278,6 +278,7 @@ const ModelableMethodRow = forwardRef( )} diff --git a/extensions/ql-vscode/src/view/model-editor/ModelInputSuggestBox.tsx b/extensions/ql-vscode/src/view/model-editor/ModelInputSuggestBox.tsx index 16ef1a330..b290dff43 100644 --- a/extensions/ql-vscode/src/view/model-editor/ModelInputSuggestBox.tsx +++ b/extensions/ql-vscode/src/view/model-editor/ModelInputSuggestBox.tsx @@ -4,7 +4,6 @@ import { calculateNewProvenance, modeledMethodSupportsInput, } from "../../model-editor/modeled-method"; -import { ReadonlyDropdown } from "../common/ReadonlyDropdown"; import type { AccessPathOption } from "../../model-editor/suggestions"; import { SuggestBox } from "../common/SuggestBox"; import { useDebounceCallback } from "../common/useDebounceCallback"; @@ -14,10 +13,12 @@ import { validateAccessPath, } from "../../model-editor/shared/access-paths"; import { ModelSuggestionIcon } from "./ModelSuggestionIcon"; +import { ModelTypePathSuggestBox } from "./ModelTypePathSuggestBox"; type Props = { modeledMethod: ModeledMethod | undefined; suggestions: AccessPathOption[]; + typePathSuggestions: AccessPathOption[]; onChange: (modeledMethod: ModeledMethod) => void; }; @@ -33,6 +34,7 @@ const getDetails = (option: AccessPathOption) => option.details; export const ModelInputSuggestBox = ({ modeledMethod, suggestions, + typePathSuggestions, onChange, }: Props) => { const [value, setValue] = useState( @@ -75,7 +77,13 @@ export const ModelInputSuggestBox = ({ ); if (modeledMethod?.type === "type") { - return ; + return ( + + ); } return ( diff --git a/extensions/ql-vscode/src/view/model-editor/ModelOutputSuggestBox.tsx b/extensions/ql-vscode/src/view/model-editor/ModelOutputSuggestBox.tsx index d7ebfc4dd..0aeb3d6de 100644 --- a/extensions/ql-vscode/src/view/model-editor/ModelOutputSuggestBox.tsx +++ b/extensions/ql-vscode/src/view/model-editor/ModelOutputSuggestBox.tsx @@ -4,7 +4,6 @@ import { calculateNewProvenance, modeledMethodSupportsOutput, } from "../../model-editor/modeled-method"; -import { ReadonlyDropdown } from "../common/ReadonlyDropdown"; import type { AccessPathOption } from "../../model-editor/suggestions"; import { SuggestBox } from "../common/SuggestBox"; import { useDebounceCallback } from "../common/useDebounceCallback"; @@ -14,6 +13,7 @@ import { validateAccessPath, } from "../../model-editor/shared/access-paths"; import { ModelSuggestionIcon } from "./ModelSuggestionIcon"; +import { ModelTypeTextbox } from "./ModelTypeTextbox"; type Props = { modeledMethod: ModeledMethod | undefined; @@ -76,8 +76,10 @@ export const ModelOutputSuggestBox = ({ if (modeledMethod?.type === "type") { return ( - ); diff --git a/extensions/ql-vscode/src/view/model-editor/ModelTypePathSuggestBox.tsx b/extensions/ql-vscode/src/view/model-editor/ModelTypePathSuggestBox.tsx new file mode 100644 index 000000000..044c65766 --- /dev/null +++ b/extensions/ql-vscode/src/view/model-editor/ModelTypePathSuggestBox.tsx @@ -0,0 +1,68 @@ +import { useEffect, useState } from "react"; +import type { TypeModeledMethod } from "../../model-editor/modeled-method"; +import type { AccessPathOption } from "../../model-editor/suggestions"; +import { SuggestBox } from "../common/SuggestBox"; +import { useDebounceCallback } from "../common/useDebounceCallback"; +import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths"; +import { + parseAccessPathTokens, + validateAccessPath, +} from "../../model-editor/shared/access-paths"; +import { ModelSuggestionIcon } from "./ModelSuggestionIcon"; + +type Props = { + modeledMethod: TypeModeledMethod; + suggestions: AccessPathOption[]; + onChange: (modeledMethod: TypeModeledMethod) => void; +}; + +const parseValueToTokens = (value: string) => + parseAccessPathTokens(value).map((t) => t.text); + +const getIcon = (option: AccessPathOption) => ( + +); + +const getDetails = (option: AccessPathOption) => option.details; + +export const ModelTypePathSuggestBox = ({ + modeledMethod, + suggestions, + onChange, +}: Props) => { + const [value, setValue] = useState(modeledMethod.path); + + useEffect(() => { + setValue(modeledMethod.path); + }, [modeledMethod]); + + // Debounce the callback to avoid updating the model too often. + // Not doing this results in a lot of lag when typing. + useDebounceCallback( + value, + (path: string | undefined) => { + if (path === undefined) { + return; + } + + onChange({ + ...modeledMethod, + path, + }); + }, + 500, + ); + + return ( + + value={value} + options={suggestions} + onChange={setValue} + parseValueToTokens={parseValueToTokens} + validateValue={validateAccessPath} + getIcon={getIcon} + getDetails={getDetails} + aria-label="Path" + /> + ); +};