Skip to content

Commit 1dc70fe

Browse files
authored
Extract model type dropdown to its own component (#2833)
1 parent 36f6531 commit 1dc70fe

3 files changed

Lines changed: 85 additions & 44 deletions

File tree

extensions/ql-vscode/src/model-editor/method.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,11 @@ export interface Method extends MethodSignature {
5757
supportedType: ModeledMethodType;
5858
usages: Usage[];
5959
}
60+
61+
export function getArgumentsList(methodParameters: string): string[] {
62+
if (methodParameters === "()") {
63+
return [];
64+
}
65+
66+
return methodParameters.substring(1, methodParameters.length - 1).split(",");
67+
}

extensions/ql-vscode/src/view/model-editor/MethodRow.tsx

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ import { styled } from "styled-components";
1010
import { vscode } from "../vscode-api";
1111

1212
import { Method } from "../../model-editor/method";
13-
import {
14-
ModeledMethod,
15-
ModeledMethodType,
16-
Provenance,
17-
} from "../../model-editor/modeled-method";
13+
import { ModeledMethod } from "../../model-editor/modeled-method";
1814
import { KindInput } from "./KindInput";
1915
import { extensiblePredicateDefinitions } from "../../model-editor/predicates";
2016
import { Mode } from "../../model-editor/shared/mode";
@@ -26,6 +22,7 @@ import {
2622
} from "./ModelingStatusIndicator";
2723
import { InProgressDropdown } from "./InProgressDropdown";
2824
import { MethodName } from "./MethodName";
25+
import { ModelTypeDropdown } from "./ModelTypeDropdown";
2926

3027
const ApiOrMethodCell = styled(VSCodeDataGridCell)`
3128
display: flex;
@@ -52,14 +49,6 @@ const ProgressRing = styled(VSCodeProgressRing)`
5249
margin-left: auto;
5350
`;
5451

55-
const modelTypeOptions: Array<{ value: ModeledMethodType; label: string }> = [
56-
{ value: "none", label: "Unmodeled" },
57-
{ value: "source", label: "Source" },
58-
{ value: "sink", label: "Sink" },
59-
{ value: "summary", label: "Flow summary" },
60-
{ value: "neutral", label: "Neutral" },
61-
];
62-
6352
export type MethodRowProps = {
6453
method: Method;
6554
methodCanBeModeled: boolean;
@@ -92,32 +81,6 @@ function ModelableMethodRow(props: MethodRowProps) {
9281
.split(",");
9382
}, [method.methodParameters]);
9483

95-
const handleTypeInput = useCallback(
96-
(e: ChangeEvent<HTMLSelectElement>) => {
97-
let newProvenance: Provenance = "manual";
98-
if (modeledMethod?.provenance === "df-generated") {
99-
newProvenance = "df-manual";
100-
} else if (modeledMethod?.provenance === "ai-generated") {
101-
newProvenance = "ai-manual";
102-
}
103-
104-
onChange(method, {
105-
// If there are no arguments, we will default to "Argument[this]"
106-
input: argumentsList.length === 0 ? "Argument[this]" : "Argument[0]",
107-
output: "ReturnValue",
108-
kind: "value",
109-
...modeledMethod,
110-
type: e.target.value as ModeledMethodType,
111-
provenance: newProvenance,
112-
signature: method.signature,
113-
packageName: method.packageName,
114-
typeName: method.typeName,
115-
methodName: method.methodName,
116-
methodParameters: method.methodParameters,
117-
});
118-
},
119-
[onChange, method, modeledMethod, argumentsList],
120-
);
12184
const handleInputInput = useCallback(
12285
(e: ChangeEvent<HTMLSelectElement>) => {
12386
if (!modeledMethod) {
@@ -235,11 +198,10 @@ function ModelableMethodRow(props: MethodRowProps) {
235198
{!props.modelingInProgress && (
236199
<>
237200
<VSCodeDataGridCell gridColumn={2}>
238-
<Dropdown
239-
value={modeledMethod?.type ?? "none"}
240-
options={modelTypeOptions}
241-
onChange={handleTypeInput}
242-
aria-label="Model type"
201+
<ModelTypeDropdown
202+
method={method}
203+
modeledMethod={modeledMethod}
204+
onChange={onChange}
243205
/>
244206
</VSCodeDataGridCell>
245207
<VSCodeDataGridCell gridColumn={3}>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as React from "react";
2+
import { ChangeEvent, useCallback, useMemo } from "react";
3+
import { Dropdown } from "../common/Dropdown";
4+
import {
5+
ModeledMethod,
6+
ModeledMethodType,
7+
Provenance,
8+
} from "../../model-editor/modeled-method";
9+
import { Method, getArgumentsList } from "../../model-editor/method";
10+
11+
const options: Array<{ value: ModeledMethodType; label: string }> = [
12+
{ value: "none", label: "Unmodeled" },
13+
{ value: "source", label: "Source" },
14+
{ value: "sink", label: "Sink" },
15+
{ value: "summary", label: "Flow summary" },
16+
{ value: "neutral", label: "Neutral" },
17+
];
18+
19+
type Props = {
20+
method: Method;
21+
modeledMethod: ModeledMethod | undefined;
22+
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
23+
};
24+
25+
export const ModelTypeDropdown = ({
26+
method,
27+
modeledMethod,
28+
onChange,
29+
}: Props): JSX.Element => {
30+
const argumentsList = useMemo(
31+
() => getArgumentsList(method.methodParameters),
32+
[method.methodParameters],
33+
);
34+
35+
const handleChange = useCallback(
36+
(e: ChangeEvent<HTMLSelectElement>) => {
37+
let newProvenance: Provenance = "manual";
38+
if (modeledMethod?.provenance === "df-generated") {
39+
newProvenance = "df-manual";
40+
} else if (modeledMethod?.provenance === "ai-generated") {
41+
newProvenance = "ai-manual";
42+
}
43+
44+
const updatedModeledMethod: ModeledMethod = {
45+
// If there are no arguments, we will default to "Argument[this]"
46+
input: argumentsList.length === 0 ? "Argument[this]" : "Argument[0]",
47+
output: "ReturnValue",
48+
kind: "value",
49+
...modeledMethod,
50+
type: e.target.value as ModeledMethodType,
51+
provenance: newProvenance,
52+
signature: method.signature,
53+
packageName: method.packageName,
54+
typeName: method.typeName,
55+
methodName: method.methodName,
56+
methodParameters: method.methodParameters,
57+
};
58+
onChange(method, updatedModeledMethod);
59+
},
60+
[onChange, method, modeledMethod, argumentsList],
61+
);
62+
63+
return (
64+
<Dropdown
65+
value={modeledMethod?.type ?? "none"}
66+
options={options}
67+
onChange={handleChange}
68+
aria-label="Model type"
69+
/>
70+
);
71+
};

0 commit comments

Comments
 (0)