Skip to content

Commit a3d41a2

Browse files
authored
Merge pull request #2924 from github/koesie10/modeling-panel-multiple-models-add-remove
Add ability to add/remove modelings to method modeling panel
2 parents 5105187 + 0cbdadb commit a3d41a2

File tree

4 files changed

+417
-6
lines changed

4 files changed

+417
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as React from "react";
2+
import { useCallback, useEffect, useState } from "react";
3+
4+
import { Meta, StoryFn } from "@storybook/react";
5+
6+
import { MultipleModeledMethodsPanel as MultipleModeledMethodsPanelComponent } from "../../view/method-modeling/MultipleModeledMethodsPanel";
7+
import { createMethod } from "../../../test/factories/model-editor/method-factories";
8+
import { createModeledMethod } from "../../../test/factories/model-editor/modeled-method-factories";
9+
import { ModeledMethod } from "../../model-editor/modeled-method";
10+
11+
export default {
12+
title: "Method Modeling/Multiple Modeled Methods Panel",
13+
component: MultipleModeledMethodsPanelComponent,
14+
} as Meta<typeof MultipleModeledMethodsPanelComponent>;
15+
16+
const Template: StoryFn<typeof MultipleModeledMethodsPanelComponent> = (
17+
args,
18+
) => {
19+
const [modeledMethods, setModeledMethods] = useState<ModeledMethod[]>(
20+
args.modeledMethods,
21+
);
22+
23+
useEffect(() => {
24+
setModeledMethods(args.modeledMethods);
25+
}, [args.modeledMethods]);
26+
27+
const handleChange = useCallback(
28+
(modeledMethods: ModeledMethod[]) => {
29+
args.onChange(modeledMethods);
30+
setModeledMethods(modeledMethods);
31+
},
32+
[args],
33+
);
34+
35+
return (
36+
<MultipleModeledMethodsPanelComponent
37+
{...args}
38+
modeledMethods={modeledMethods}
39+
onChange={handleChange}
40+
/>
41+
);
42+
};
43+
44+
const method = createMethod();
45+
46+
export const Unmodeled = Template.bind({});
47+
Unmodeled.args = {
48+
method,
49+
modeledMethods: [],
50+
};
51+
52+
export const Single = Template.bind({});
53+
Single.args = {
54+
method,
55+
modeledMethods: [createModeledMethod(method)],
56+
};
57+
58+
export const Multiple = Template.bind({});
59+
Multiple.args = {
60+
method,
61+
modeledMethods: [
62+
createModeledMethod(method),
63+
createModeledMethod({
64+
...method,
65+
type: "source",
66+
input: "",
67+
output: "ReturnValue",
68+
kind: "remote",
69+
}),
70+
],
71+
};

extensions/ql-vscode/src/view/method-modeling/ModeledMethodsPanel.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from "react";
2+
import { useCallback } from "react";
23
import { ModeledMethod } from "../../model-editor/modeled-method";
34
import { MethodModelingInputs } from "./MethodModelingInputs";
45
import { Method } from "../../model-editor/method";
@@ -23,6 +24,13 @@ export const ModeledMethodsPanel = ({
2324
showMultipleModels,
2425
onChange,
2526
}: ModeledMethodsPanelProps) => {
27+
const handleMultipleChange = useCallback(
28+
(modeledMethods: ModeledMethod[]) => {
29+
onChange(modeledMethods[0]);
30+
},
31+
[onChange],
32+
);
33+
2634
if (!showMultipleModels) {
2735
return (
2836
<SingleMethodModelingInputs
@@ -37,7 +45,7 @@ export const ModeledMethodsPanel = ({
3745
<MultipleModeledMethodsPanel
3846
method={method}
3947
modeledMethods={modeledMethods}
40-
onChange={onChange}
48+
onChange={handleMultipleChange}
4149
/>
4250
);
4351
};

extensions/ql-vscode/src/view/method-modeling/MultipleModeledMethodsPanel.tsx

+83-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import { useCallback, useState } from "react";
2+
import { useCallback, useMemo, useState } from "react";
33
import { Method } from "../../model-editor/method";
44
import { ModeledMethod } from "../../model-editor/modeled-method";
55
import { styled } from "styled-components";
@@ -10,7 +10,7 @@ import { Codicon } from "../common";
1010
export type MultipleModeledMethodsPanelProps = {
1111
method: Method;
1212
modeledMethods: ModeledMethod[];
13-
onChange: (modeledMethod: ModeledMethod) => void;
13+
onChange: (modeledMethods: ModeledMethod[]) => void;
1414
};
1515

1616
const Container = styled.div`
@@ -25,6 +25,7 @@ const Container = styled.div`
2525
const Footer = styled.div`
2626
display: flex;
2727
flex-direction: row;
28+
justify-content: space-between;
2829
`;
2930

3031
const PaginationActions = styled.div`
@@ -33,6 +34,12 @@ const PaginationActions = styled.div`
3334
gap: 0.5rem;
3435
`;
3536

37+
const ModificationActions = styled.div`
38+
display: flex;
39+
flex-direction: row;
40+
gap: 0.5rem;
41+
`;
42+
3643
export const MultipleModeledMethodsPanel = ({
3744
method,
3845
modeledMethods,
@@ -47,19 +54,73 @@ export const MultipleModeledMethodsPanel = ({
4754
setSelectedIndex((previousIndex) => previousIndex + 1);
4855
}, []);
4956

57+
const handleAddClick = useCallback(() => {
58+
const newModeledMethod: ModeledMethod = {
59+
type: "none",
60+
input: "",
61+
output: "",
62+
kind: "",
63+
provenance: "manual",
64+
signature: method.signature,
65+
packageName: method.packageName,
66+
typeName: method.typeName,
67+
methodName: method.methodName,
68+
methodParameters: method.methodParameters,
69+
};
70+
71+
const newModeledMethods = [...modeledMethods, newModeledMethod];
72+
73+
onChange(newModeledMethods);
74+
setSelectedIndex(newModeledMethods.length - 1);
75+
}, [onChange, modeledMethods, method]);
76+
77+
const handleRemoveClick = useCallback(() => {
78+
const newModeledMethods = modeledMethods.filter(
79+
(_, index) => index !== selectedIndex,
80+
);
81+
82+
const newSelectedIndex =
83+
selectedIndex === newModeledMethods.length
84+
? selectedIndex - 1
85+
: selectedIndex;
86+
87+
onChange(newModeledMethods);
88+
setSelectedIndex(newSelectedIndex);
89+
}, [onChange, modeledMethods, selectedIndex]);
90+
91+
const anyUnmodeled = useMemo(
92+
() =>
93+
modeledMethods.length === 0 ||
94+
modeledMethods.some((m) => m.type === "none"),
95+
[modeledMethods],
96+
);
97+
98+
const handleChange = useCallback(
99+
(modeledMethod: ModeledMethod) => {
100+
if (modeledMethods.length > 0) {
101+
const newModeledMethods = [...modeledMethods];
102+
newModeledMethods[selectedIndex] = modeledMethod;
103+
onChange(newModeledMethods);
104+
} else {
105+
onChange([modeledMethod]);
106+
}
107+
},
108+
[modeledMethods, selectedIndex, onChange],
109+
);
110+
50111
return (
51112
<Container>
52113
{modeledMethods.length > 0 ? (
53114
<MethodModelingInputs
54115
method={method}
55116
modeledMethod={modeledMethods[selectedIndex]}
56-
onChange={onChange}
117+
onChange={handleChange}
57118
/>
58119
) : (
59120
<MethodModelingInputs
60121
method={method}
61122
modeledMethod={undefined}
62-
onChange={onChange}
123+
onChange={handleChange}
63124
/>
64125
)}
65126
<Footer>
@@ -89,6 +150,24 @@ export const MultipleModeledMethodsPanel = ({
89150
<Codicon name="chevron-right" />
90151
</VSCodeButton>
91152
</PaginationActions>
153+
<ModificationActions>
154+
<VSCodeButton
155+
appearance="icon"
156+
aria-label="Delete modeling"
157+
onClick={handleRemoveClick}
158+
disabled={modeledMethods.length < 2}
159+
>
160+
<Codicon name="trash" />
161+
</VSCodeButton>
162+
<VSCodeButton
163+
appearance="icon"
164+
aria-label="Add modeling"
165+
onClick={handleAddClick}
166+
disabled={anyUnmodeled}
167+
>
168+
<Codicon name="add" />
169+
</VSCodeButton>
170+
</ModificationActions>
92171
</Footer>
93172
</Container>
94173
);

0 commit comments

Comments
 (0)