Skip to content

Commit 4dae9b8

Browse files
committed
Add ability to add/remove modelings
1 parent 5c368ce commit 4dae9b8

File tree

4 files changed

+416
-6
lines changed

4 files changed

+416
-6
lines changed
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 { 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

Lines changed: 9 additions & 1 deletion
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";
@@ -22,6 +23,13 @@ export const ModeledMethodsPanel = ({
2223
showMultipleModels,
2324
onChange,
2425
}: ModeledMethodsPanelProps) => {
26+
const handleMultipleChange = useCallback(
27+
(modeledMethods: ModeledMethod[]) => {
28+
onChange(modeledMethods[0]);
29+
},
30+
[onChange],
31+
);
32+
2533
if (!showMultipleModels) {
2634
return (
2735
<SingleMethodModelingInputs
@@ -38,7 +46,7 @@ export const ModeledMethodsPanel = ({
3846
<MultipleModeledMethodsPanel
3947
method={method}
4048
modeledMethods={modeledMethods}
41-
onChange={onChange}
49+
onChange={handleMultipleChange}
4250
/>
4351
);
4452
};

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

Lines changed: 82 additions & 4 deletions
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,72 @@ 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+
const handleRemoveClick = useCallback(() => {
77+
const newModeledMethods = modeledMethods.filter(
78+
(_, index) => index !== selectedIndex,
79+
);
80+
81+
const newSelectedIndex =
82+
selectedIndex === newModeledMethods.length
83+
? selectedIndex - 1
84+
: selectedIndex;
85+
86+
onChange(newModeledMethods);
87+
setSelectedIndex(newSelectedIndex);
88+
}, [onChange, modeledMethods, selectedIndex]);
89+
90+
const anyUnmodeled = useMemo(
91+
() =>
92+
modeledMethods.length === 0 ||
93+
modeledMethods.some((m) => m.type === "none"),
94+
[modeledMethods],
95+
);
96+
97+
const handleChange = useCallback(
98+
(modeledMethod: ModeledMethod) => {
99+
if (modeledMethods.length > 0) {
100+
const newModeledMethods = [...modeledMethods];
101+
newModeledMethods[selectedIndex] = modeledMethod;
102+
onChange(newModeledMethods);
103+
} else {
104+
onChange([modeledMethod]);
105+
}
106+
},
107+
[modeledMethods, selectedIndex, onChange],
108+
);
109+
50110
return (
51111
<Container>
52112
{modeledMethods.length > 0 ? (
53113
<MethodModelingInputs
54114
method={method}
55115
modeledMethod={modeledMethods[selectedIndex]}
56-
onChange={onChange}
116+
onChange={handleChange}
57117
/>
58118
) : (
59119
<MethodModelingInputs
60120
method={method}
61121
modeledMethod={undefined}
62-
onChange={onChange}
122+
onChange={handleChange}
63123
/>
64124
)}
65125
<Footer>
@@ -89,6 +149,24 @@ export const MultipleModeledMethodsPanel = ({
89149
<Codicon name="chevron-right" />
90150
</VSCodeButton>
91151
</PaginationActions>
152+
<ModificationActions>
153+
<VSCodeButton
154+
appearance="icon"
155+
aria-label="Delete modeling"
156+
onClick={handleRemoveClick}
157+
disabled={modeledMethods.length < 2}
158+
>
159+
<Codicon name="trash" />
160+
</VSCodeButton>
161+
<VSCodeButton
162+
appearance="icon"
163+
aria-label="Add modeling"
164+
onClick={handleAddClick}
165+
disabled={anyUnmodeled}
166+
>
167+
<Codicon name="add" />
168+
</VSCodeButton>
169+
</ModificationActions>
92170
</Footer>
93171
</Container>
94172
);

0 commit comments

Comments
 (0)