Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 6 additions & 46 deletions extensions/ql-vscode/src/view/model-editor/MethodRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
VSCodeProgressRing,
} from "@vscode/webview-ui-toolkit/react";
import * as React from "react";
import { ChangeEvent, useCallback, useMemo } from "react";
import { useCallback } from "react";
import { styled } from "styled-components";
import { vscode } from "../vscode-api";

Expand All @@ -14,7 +14,6 @@ import { ModeledMethod } from "../../model-editor/modeled-method";
import { KindInput } from "./KindInput";
import { extensiblePredicateDefinitions } from "../../model-editor/predicates";
import { Mode } from "../../model-editor/shared/mode";
import { Dropdown } from "../common/Dropdown";
import { MethodClassifications } from "./MethodClassifications";
import {
ModelingStatus,
Expand All @@ -24,6 +23,7 @@ import { InProgressDropdown } from "./InProgressDropdown";
import { MethodName } from "./MethodName";
import { ModelTypeDropdown } from "./ModelTypeDropdown";
import { ModelInputDropdown } from "./ModelInputDropdown";
import { ModelOutputDropdown } from "./ModelOutputDropdown";

const ApiOrMethodCell = styled(VSCodeDataGridCell)`
display: flex;
Expand Down Expand Up @@ -73,30 +73,6 @@ export const MethodRow = (props: MethodRowProps) => {
function ModelableMethodRow(props: MethodRowProps) {
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;

const argumentsList = useMemo(() => {
if (method.methodParameters === "()") {
return [];
}
return method.methodParameters
.substring(1, method.methodParameters.length - 1)
.split(",");
}, [method.methodParameters]);

const handleOutputInput = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
if (!modeledMethod) {
return;
}

const target = e.target as HTMLSelectElement;

onChange(method, {
...modeledMethod,
output: target.value,
});
},
[onChange, method, modeledMethod],
);
const handleKindChange = useCallback(
(kind: string) => {
if (!modeledMethod) {
Expand All @@ -116,20 +92,6 @@ function ModelableMethodRow(props: MethodRowProps) {
[method],
);

const outputOptions = useMemo(
() => [
{ value: "ReturnValue", label: "ReturnValue" },
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);

const showOutputCell =
modeledMethod?.type && ["source", "summary"].includes(modeledMethod?.type);
const predicate =
modeledMethod?.type && modeledMethod.type !== "none"
? extensiblePredicateDefinitions[modeledMethod.type]
Expand Down Expand Up @@ -185,12 +147,10 @@ function ModelableMethodRow(props: MethodRowProps) {
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
<Dropdown
value={modeledMethod?.output}
options={outputOptions}
disabled={!showOutputCell}
onChange={handleOutputInput}
aria-label="Output"
<ModelOutputDropdown
method={method}
modeledMethod={modeledMethod}
onChange={onChange}
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from "react";
import { ChangeEvent, useCallback, useMemo } from "react";
import { Dropdown } from "../common/Dropdown";
import { ModeledMethod } from "../../model-editor/modeled-method";
import { Method, getArgumentsList } from "../../model-editor/method";

type Props = {
method: Method;
modeledMethod: ModeledMethod | undefined;
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
};

export const ModelOutputDropdown = ({
method,
modeledMethod,
onChange,
}: Props): JSX.Element => {
const argumentsList = useMemo(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

argumentList is only used to compute options, so we could merge these together and call geArgumentList on line 27 and it wouldn't change any behaviour. What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point. I could do the same in ModelInputDropdown.

If we keep things as is we would be consistent with ModelInputDropdown and ModelTypeDropdown though.

I don't have strong opinions.

() => getArgumentsList(method.methodParameters),
[method.methodParameters],
);

const options = useMemo(
() => [
{ value: "ReturnValue", label: "ReturnValue" },
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);

const enabled = useMemo(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a primitive type and the value is not hard to compute, I don't believe we gain anything by using useMemo. If you'd prefer to not make any changes in this PR I'm happy to open it as a followup.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm following the same pattern as in #2837 so I'd rather keep it consistent. Happy to stick to useMemo or drop it, but would rather do the same across the board.

() =>
modeledMethod?.type &&
["source", "summary"].includes(modeledMethod?.type),
[modeledMethod?.type],
);

const handleChange = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
if (!modeledMethod) {
return;
}

const target = e.target as HTMLSelectElement;

onChange(method, {
...modeledMethod,
output: target.value,
});
},
[onChange, method, modeledMethod],
);

return (
<Dropdown
value={modeledMethod?.output}
options={options}
disabled={!enabled}
onChange={handleChange}
aria-label="Output"
/>
);
};