CodeQL model editor: Use suggest box for type path suggestions (#3316)
This commit is contained in:
@@ -278,6 +278,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||||||
<ModelInputSuggestBox
|
<ModelInputSuggestBox
|
||||||
modeledMethod={modeledMethod}
|
modeledMethod={modeledMethod}
|
||||||
suggestions={inputAccessPathSuggestions}
|
suggestions={inputAccessPathSuggestions}
|
||||||
|
typePathSuggestions={outputAccessPathSuggestions ?? []}
|
||||||
onChange={modeledMethodChangedHandlers[index]}
|
onChange={modeledMethodChangedHandlers[index]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
calculateNewProvenance,
|
calculateNewProvenance,
|
||||||
modeledMethodSupportsInput,
|
modeledMethodSupportsInput,
|
||||||
} from "../../model-editor/modeled-method";
|
} from "../../model-editor/modeled-method";
|
||||||
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
|
|
||||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||||
import { SuggestBox } from "../common/SuggestBox";
|
import { SuggestBox } from "../common/SuggestBox";
|
||||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||||
@@ -14,10 +13,12 @@ import {
|
|||||||
validateAccessPath,
|
validateAccessPath,
|
||||||
} from "../../model-editor/shared/access-paths";
|
} from "../../model-editor/shared/access-paths";
|
||||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||||
|
import { ModelTypePathSuggestBox } from "./ModelTypePathSuggestBox";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modeledMethod: ModeledMethod | undefined;
|
modeledMethod: ModeledMethod | undefined;
|
||||||
suggestions: AccessPathOption[];
|
suggestions: AccessPathOption[];
|
||||||
|
typePathSuggestions: AccessPathOption[];
|
||||||
onChange: (modeledMethod: ModeledMethod) => void;
|
onChange: (modeledMethod: ModeledMethod) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ const getDetails = (option: AccessPathOption) => option.details;
|
|||||||
export const ModelInputSuggestBox = ({
|
export const ModelInputSuggestBox = ({
|
||||||
modeledMethod,
|
modeledMethod,
|
||||||
suggestions,
|
suggestions,
|
||||||
|
typePathSuggestions,
|
||||||
onChange,
|
onChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [value, setValue] = useState<string | undefined>(
|
const [value, setValue] = useState<string | undefined>(
|
||||||
@@ -75,7 +77,13 @@ export const ModelInputSuggestBox = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (modeledMethod?.type === "type") {
|
if (modeledMethod?.type === "type") {
|
||||||
return <ReadonlyDropdown value={modeledMethod.path} aria-label="Path" />;
|
return (
|
||||||
|
<ModelTypePathSuggestBox
|
||||||
|
modeledMethod={modeledMethod}
|
||||||
|
suggestions={typePathSuggestions}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
calculateNewProvenance,
|
calculateNewProvenance,
|
||||||
modeledMethodSupportsOutput,
|
modeledMethodSupportsOutput,
|
||||||
} from "../../model-editor/modeled-method";
|
} from "../../model-editor/modeled-method";
|
||||||
import { ReadonlyDropdown } from "../common/ReadonlyDropdown";
|
|
||||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||||
import { SuggestBox } from "../common/SuggestBox";
|
import { SuggestBox } from "../common/SuggestBox";
|
||||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||||
@@ -14,6 +13,7 @@ import {
|
|||||||
validateAccessPath,
|
validateAccessPath,
|
||||||
} from "../../model-editor/shared/access-paths";
|
} from "../../model-editor/shared/access-paths";
|
||||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||||
|
import { ModelTypeTextbox } from "./ModelTypeTextbox";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modeledMethod: ModeledMethod | undefined;
|
modeledMethod: ModeledMethod | undefined;
|
||||||
@@ -76,8 +76,10 @@ export const ModelOutputSuggestBox = ({
|
|||||||
|
|
||||||
if (modeledMethod?.type === "type") {
|
if (modeledMethod?.type === "type") {
|
||||||
return (
|
return (
|
||||||
<ReadonlyDropdown
|
<ModelTypeTextbox
|
||||||
value={modeledMethod.relatedTypeName}
|
modeledMethod={modeledMethod}
|
||||||
|
typeInfo="relatedTypeName"
|
||||||
|
onChange={onChange}
|
||||||
aria-label="Related type name"
|
aria-label="Related type name"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user