CodeQL model editor: Use suggest box for type path suggestions (#3316)

This commit is contained in:
Shati Patel
2024-02-06 15:11:56 +00:00
committed by GitHub
parent 6030137f43
commit 19d85a73e1
4 changed files with 84 additions and 5 deletions

View File

@@ -278,6 +278,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
<ModelInputSuggestBox
modeledMethod={modeledMethod}
suggestions={inputAccessPathSuggestions}
typePathSuggestions={outputAccessPathSuggestions ?? []}
onChange={modeledMethodChangedHandlers[index]}
/>
)}

View File

@@ -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<string | undefined>(
@@ -75,7 +77,13 @@ export const ModelInputSuggestBox = ({
);
if (modeledMethod?.type === "type") {
return <ReadonlyDropdown value={modeledMethod.path} aria-label="Path" />;
return (
<ModelTypePathSuggestBox
modeledMethod={modeledMethod}
suggestions={typePathSuggestions}
onChange={onChange}
/>
);
}
return (

View File

@@ -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 (
<ReadonlyDropdown
value={modeledMethod.relatedTypeName}
<ModelTypeTextbox
modeledMethod={modeledMethod}
typeInfo="relatedTypeName"
onChange={onChange}
aria-label="Related type name"
/>
);

View File

@@ -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) => (
<ModelSuggestionIcon name={option.icon} />
);
const getDetails = (option: AccessPathOption) => option.details;
export const ModelTypePathSuggestBox = ({
modeledMethod,
suggestions,
onChange,
}: Props) => {
const [value, setValue] = useState<string | undefined>(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 (
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
value={value}
options={suggestions}
onChange={setValue}
parseValueToTokens={parseValueToTokens}
validateValue={validateAccessPath}
getIcon={getIcon}
getDetails={getDetails}
aria-label="Path"
/>
);
};