Skip to content

Commit a01a76c

Browse files
committed
Add initial multiple modelings panel
1 parent a29112e commit a01a76c

File tree

6 files changed

+202
-11
lines changed

6 files changed

+202
-11
lines changed

extensions/ql-vscode/src/stories/method-modeling/MethodModeling.stories.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,24 @@ MethodSaved.args = {
3737
modelingStatus: "saved",
3838
};
3939

40-
export const MultipleModelings = Template.bind({});
41-
MultipleModelings.args = {
40+
export const MultipleModelingsUnmodeled = Template.bind({});
41+
MultipleModelingsUnmodeled.args = {
42+
method,
43+
modeledMethods: [],
44+
showMultipleModels: true,
45+
modelingStatus: "saved",
46+
};
47+
48+
export const MultipleModelingsModeledSingle = Template.bind({});
49+
MultipleModelingsModeledSingle.args = {
50+
method,
51+
modeledMethods: [createModeledMethod(method)],
52+
showMultipleModels: true,
53+
modelingStatus: "saved",
54+
};
55+
56+
export const MultipleModelingsModeledMultiple = Template.bind({});
57+
MultipleModelingsModeledMultiple.args = {
4258
method,
4359
modeledMethods: [
4460
createModeledMethod(method),
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from "react";
2+
import { styled } from "styled-components";
3+
import classNames from "classnames";
4+
5+
type Size = "x-small" | "small" | "medium" | "large" | "x-large";
6+
7+
const StyledButton = styled.button<{ size: Size }>`
8+
background: none;
9+
color: var(--vscode-textLink-foreground);
10+
border: none;
11+
cursor: pointer;
12+
font-size: ${(props) => props.size ?? "1em"};
13+
padding: 0;
14+
vertical-align: text-bottom;
15+
16+
&:disabled {
17+
color: var(--vscode-disabledForeground);
18+
cursor: default;
19+
}
20+
`;
21+
22+
export const CodiconButton = ({
23+
size,
24+
onClick,
25+
className,
26+
name,
27+
label,
28+
disabled,
29+
}: {
30+
size?: Size;
31+
onClick: (e: React.MouseEvent) => void;
32+
className?: string;
33+
name: string;
34+
label: string;
35+
disabled?: boolean;
36+
}) => (
37+
<StyledButton
38+
size={size}
39+
onClick={onClick}
40+
className={className}
41+
disabled={disabled}
42+
>
43+
<span
44+
role="img"
45+
aria-label={label}
46+
title={label}
47+
className={classNames("codicon", `codicon-${name}`, className)}
48+
/>
49+
</StyledButton>
50+
);

extensions/ql-vscode/src/view/common/icon/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./Codicon";
2+
export * from "./CodiconButton";
23
export * from "./ErrorIcon";
34
export * from "./LoadingIcon";
45
export * from "./SuccessIcon";

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { ModelingStatusIndicator } from "../model-editor/ModelingStatusIndicator
55
import { Method } from "../../model-editor/method";
66
import { MethodName } from "../model-editor/MethodName";
77
import { ModeledMethod } from "../../model-editor/modeled-method";
8-
import { MethodModelingInputs } from "./MethodModelingInputs";
98
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
109
import { ReviewInEditorButton } from "./ReviewInEditorButton";
10+
import { ModeledMethodsPanel } from "./ModeledMethodsPanel";
1111

1212
const Container = styled.div`
1313
padding-top: 0.5rem;
@@ -38,10 +38,6 @@ const DependencyContainer = styled.div`
3838
margin-bottom: 0.8rem;
3939
`;
4040

41-
const StyledMethodModelingInputs = styled(MethodModelingInputs)`
42-
padding-bottom: 0.5rem;
43-
`;
44-
4541
const StyledVSCodeTag = styled(VSCodeTag)<{ visible: boolean }>`
4642
visibility: ${(props) => (props.visible ? "visible" : "hidden")};
4743
`;
@@ -64,6 +60,7 @@ export const MethodModeling = ({
6460
modelingStatus,
6561
modeledMethods,
6662
method,
63+
showMultipleModels = false,
6764
onChange,
6865
}: MethodModelingProps): JSX.Element => {
6966
return (
@@ -77,11 +74,10 @@ export const MethodModeling = ({
7774
<ModelingStatusIndicator status={modelingStatus} />
7875
<MethodName {...method} />
7976
</DependencyContainer>
80-
<StyledMethodModelingInputs
77+
<ModeledMethodsPanel
8178
method={method}
82-
modeledMethod={
83-
modeledMethods.length > 0 ? modeledMethods[0] : undefined
84-
}
79+
modeledMethods={modeledMethods}
80+
showMultipleModels={showMultipleModels}
8581
onChange={onChange}
8682
/>
8783
<ReviewInEditorButton method={method} />
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as React from "react";
2+
import { ModeledMethod } from "../../model-editor/modeled-method";
3+
import { MethodModelingInputs } from "./MethodModelingInputs";
4+
import { Method } from "../../model-editor/method";
5+
import { styled } from "styled-components";
6+
import { MultipleModeledMethodsPanel } from "./MultipleModeledMethodsPanel";
7+
8+
type Props = {
9+
method: Method;
10+
modeledMethods: ModeledMethod[];
11+
showMultipleModels: boolean;
12+
onChange: (modeledMethod: ModeledMethod) => void;
13+
};
14+
15+
const SingleMethodModelingInputs = styled(MethodModelingInputs)`
16+
padding-bottom: 0.5rem;
17+
`;
18+
19+
export const ModeledMethodsPanel = ({
20+
method,
21+
modeledMethods,
22+
showMultipleModels,
23+
onChange,
24+
}: Props) => {
25+
if (!showMultipleModels) {
26+
return (
27+
<SingleMethodModelingInputs
28+
method={method}
29+
modeledMethod={
30+
modeledMethods.length > 0 ? modeledMethods[0] : undefined
31+
}
32+
onChange={onChange}
33+
/>
34+
);
35+
}
36+
37+
return (
38+
<MultipleModeledMethodsPanel
39+
method={method}
40+
modeledMethods={modeledMethods}
41+
onChange={onChange}
42+
/>
43+
);
44+
};
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import * as React from "react";
2+
import { useCallback, useState } from "react";
3+
import { Method } from "../../model-editor/method";
4+
import { ModeledMethod } from "../../model-editor/modeled-method";
5+
import { styled } from "styled-components";
6+
import { MethodModelingInputs } from "./MethodModelingInputs";
7+
import { CodiconButton } from "../common";
8+
9+
type Props = {
10+
method: Method;
11+
modeledMethods: ModeledMethod[];
12+
onChange: (modeledMethod: ModeledMethod) => void;
13+
};
14+
15+
const Container = styled.div`
16+
display: flex;
17+
flex-direction: column;
18+
gap: 0.25rem;
19+
20+
padding-bottom: 0.5rem;
21+
border-bottom: 0.05rem solid var(--vscode-panelSection-border);
22+
`;
23+
24+
const Footer = styled.div`
25+
display: flex;
26+
flex-direction: row;
27+
`;
28+
29+
const PaginationActions = styled.div`
30+
display: flex;
31+
flex-direction: row;
32+
gap: 0.5rem;
33+
`;
34+
35+
export const MultipleModeledMethodsPanel = ({
36+
method,
37+
modeledMethods,
38+
onChange,
39+
}: Props) => {
40+
const [selectedIndex, setSelectedIndex] = useState<number>(0);
41+
42+
const handlePreviousClick = useCallback(() => {
43+
setSelectedIndex((previousIndex) => previousIndex - 1);
44+
}, []);
45+
const handleNextClick = useCallback(() => {
46+
setSelectedIndex((previousIndex) => previousIndex + 1);
47+
}, []);
48+
49+
return (
50+
<Container>
51+
{modeledMethods.length > 0 && (
52+
<MethodModelingInputs
53+
method={method}
54+
modeledMethod={modeledMethods[selectedIndex]}
55+
onChange={onChange}
56+
/>
57+
)}
58+
<Footer>
59+
<PaginationActions>
60+
<CodiconButton
61+
name="chevron-left"
62+
label="Previous modeling"
63+
onClick={handlePreviousClick}
64+
disabled={modeledMethods.length < 2 || selectedIndex === 0}
65+
/>
66+
{modeledMethods.length > 1 && (
67+
<div>
68+
{selectedIndex + 1}/{modeledMethods.length}
69+
</div>
70+
)}
71+
<CodiconButton
72+
name="chevron-right"
73+
label="Next modeling"
74+
onClick={handleNextClick}
75+
disabled={
76+
modeledMethods.length < 2 ||
77+
selectedIndex === modeledMethods.length - 1
78+
}
79+
/>
80+
</PaginationActions>
81+
</Footer>
82+
</Container>
83+
);
84+
};

0 commit comments

Comments
 (0)