Skip to content

Commit 7ed997b

Browse files
refactor: WSEditorCommandGroupContent to function-based
1 parent cafe4dc commit 7ed997b

File tree

3 files changed

+302
-282
lines changed

3 files changed

+302
-282
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import {
2+
Box,
3+
Button,
4+
Dialog,
5+
DialogActions,
6+
DialogContent,
7+
DialogTitle,
8+
LinearProgress,
9+
Typography,
10+
} from "@mui/material";
11+
import { commandApi } from "../../services";
12+
import * as React from "react";
13+
import { CommandGroup } from "./WSEditorCommandGroupContent";
14+
15+
const commandPrefix = "az ";
16+
17+
function CommandGroupDeleteDialog(props: {
18+
workspaceUrl: string;
19+
open: boolean;
20+
commandGroup: CommandGroup;
21+
onClose: (deleted: boolean) => void;
22+
}) {
23+
const [updating, setUpdating] = React.useState<boolean>(false);
24+
25+
const handleClose = () => {
26+
props.onClose(false);
27+
};
28+
const handleDelete = async () => {
29+
const nodeUrl = `${props.workspaceUrl}/CommandTree/Nodes/aaz/` + props.commandGroup.names.join("/");
30+
setUpdating(true);
31+
32+
try {
33+
await commandApi.deleteCommandGroup(nodeUrl);
34+
setUpdating(false);
35+
props.onClose(true);
36+
} catch (err: any) {
37+
setUpdating(false);
38+
console.error(err);
39+
}
40+
};
41+
42+
return (
43+
<Dialog disableEscapeKeyDown open={props.open}>
44+
<DialogTitle>Delete Command Group</DialogTitle>
45+
<DialogContent dividers={true}>
46+
<Typography variant="body2">{`${commandPrefix}${props.commandGroup.names.join(" ")}`}</Typography>
47+
</DialogContent>
48+
<DialogActions>
49+
{updating && (
50+
<Box sx={{ width: "100%" }}>
51+
<LinearProgress color="secondary" />
52+
</Box>
53+
)}
54+
{!updating && (
55+
<React.Fragment>
56+
<Button onClick={handleClose}>Cancel</Button>
57+
<Button onClick={handleDelete}>Delete</Button>
58+
</React.Fragment>
59+
)}
60+
</DialogActions>
61+
</Dialog>
62+
);
63+
}
64+
65+
export default CommandGroupDeleteDialog;
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import {
2+
Alert,
3+
Box,
4+
Button,
5+
Dialog,
6+
DialogActions,
7+
DialogContent,
8+
DialogTitle,
9+
FormControlLabel,
10+
InputLabel,
11+
LinearProgress,
12+
Radio,
13+
RadioGroup,
14+
TextField,
15+
} from "@mui/material";
16+
import { commandApi, errorHandlerApi } from "../../services";
17+
import * as React from "react";
18+
import { CommandGroup, DecodeResponseCommandGroup } from "./WSEditorCommandGroupContent";
19+
20+
interface CommandGroupDialogProps {
21+
workspaceUrl: string;
22+
open: boolean;
23+
commandGroup: CommandGroup;
24+
onClose: (newCommandGroup?: CommandGroup) => void;
25+
}
26+
27+
interface CommandGroupDialogState {
28+
name: string;
29+
stage: string;
30+
shortHelp: string;
31+
longHelp: string;
32+
invalidText?: string;
33+
updating: boolean;
34+
}
35+
36+
class CommandGroupDialog extends React.Component<CommandGroupDialogProps, CommandGroupDialogState> {
37+
constructor(props: CommandGroupDialogProps) {
38+
super(props);
39+
this.state = {
40+
name: this.props.commandGroup.names.join(" "),
41+
shortHelp: this.props.commandGroup.help?.short ?? "",
42+
longHelp: this.props.commandGroup.help?.lines?.join("\n") ?? "",
43+
stage: this.props.commandGroup.stage,
44+
updating: false,
45+
};
46+
}
47+
48+
handleModify = async () => {
49+
let { name, shortHelp, longHelp } = this.state;
50+
const { stage } = this.state;
51+
const { workspaceUrl, commandGroup } = this.props;
52+
53+
name = name.trim();
54+
shortHelp = shortHelp.trim();
55+
longHelp = longHelp.trim();
56+
57+
const names = name.split(" ").filter((n) => n.length > 0);
58+
59+
this.setState({
60+
invalidText: undefined,
61+
});
62+
63+
if (names.length < 1) {
64+
this.setState({
65+
invalidText: `Field 'Name' is required.`,
66+
});
67+
return;
68+
}
69+
70+
for (const idx in names) {
71+
const piece = names[idx];
72+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(piece)) {
73+
this.setState({
74+
invalidText: `Invalid Name part: '${piece}'. Supported regular expression is: [a-z0-9]+(-[a-z0-9]+)* `,
75+
});
76+
return;
77+
}
78+
}
79+
80+
if (shortHelp.length < 1) {
81+
this.setState({
82+
invalidText: `Field 'Short Summary' is required.`,
83+
});
84+
}
85+
86+
let lines: string[] = [];
87+
if (longHelp.length > 1) {
88+
lines = longHelp.split("\n").filter((l) => l.length > 0);
89+
}
90+
91+
this.setState({
92+
updating: true,
93+
});
94+
95+
const nodeUrl = `${workspaceUrl}/CommandTree/Nodes/aaz/` + commandGroup.names.join("/");
96+
97+
try {
98+
const res = await commandApi.updateCommandGroup(nodeUrl, {
99+
help: {
100+
short: shortHelp,
101+
lines: lines,
102+
},
103+
stage: stage,
104+
});
105+
106+
const name = names.join(" ");
107+
if (name === commandGroup.names.join(" ")) {
108+
const cmdGroup = DecodeResponseCommandGroup(res);
109+
this.setState({
110+
updating: false,
111+
});
112+
this.props.onClose(cmdGroup);
113+
} else {
114+
const renameRes = await commandApi.renameCommandGroup(nodeUrl, name);
115+
const cmdGroup = DecodeResponseCommandGroup(renameRes);
116+
this.setState({
117+
updating: false,
118+
});
119+
this.props.onClose(cmdGroup);
120+
}
121+
} catch (err: any) {
122+
console.error(err);
123+
this.setState({
124+
updating: false,
125+
invalidText: errorHandlerApi.getErrorMessage(err),
126+
});
127+
}
128+
};
129+
130+
handleClose = () => {
131+
this.setState({
132+
invalidText: undefined,
133+
});
134+
this.props.onClose();
135+
};
136+
137+
render() {
138+
const { name, shortHelp, longHelp, invalidText, updating, stage } = this.state;
139+
return (
140+
<Dialog disableEscapeKeyDown open={this.props.open} sx={{ "& .MuiDialog-paper": { width: "80%" } }}>
141+
<DialogTitle>Command Group</DialogTitle>
142+
<DialogContent dividers={true}>
143+
{invalidText && (
144+
<Alert variant="filled" severity="error">
145+
{" "}
146+
{invalidText}{" "}
147+
</Alert>
148+
)}
149+
150+
<InputLabel required shrink sx={{ font: "inherit" }}>
151+
Stage
152+
</InputLabel>
153+
<RadioGroup
154+
row
155+
value={stage}
156+
name="stage"
157+
onChange={(event: any) => {
158+
this.setState({
159+
stage: event.target.value,
160+
});
161+
}}
162+
>
163+
<FormControlLabel value="Stable" control={<Radio />} label="Stable" sx={{ ml: 4 }} />
164+
<FormControlLabel value="Preview" control={<Radio />} label="Preview" sx={{ ml: 4 }} />
165+
<FormControlLabel value="Experimental" control={<Radio />} label="Experimental" sx={{ ml: 4 }} />
166+
</RadioGroup>
167+
168+
<TextField
169+
id="name"
170+
label="Name"
171+
type="text"
172+
fullWidth
173+
variant="standard"
174+
value={name}
175+
onChange={(event: any) => {
176+
this.setState({
177+
name: event.target.value,
178+
});
179+
}}
180+
margin="normal"
181+
required
182+
/>
183+
<TextField
184+
id="shortSummary"
185+
label="Short Summary"
186+
type="text"
187+
fullWidth
188+
variant="standard"
189+
value={shortHelp}
190+
onChange={(event: any) => {
191+
this.setState({
192+
shortHelp: event.target.value,
193+
});
194+
}}
195+
margin="normal"
196+
required
197+
/>
198+
<TextField
199+
id="longSummary"
200+
label="Long Summary"
201+
helperText="Please add long summary in lines."
202+
type="text"
203+
fullWidth
204+
multiline
205+
rows={4}
206+
variant="standard"
207+
value={longHelp}
208+
onChange={(event: any) => {
209+
this.setState({
210+
longHelp: event.target.value,
211+
});
212+
}}
213+
margin="normal"
214+
/>
215+
</DialogContent>
216+
<DialogActions>
217+
{updating && (
218+
<Box sx={{ width: "100%" }}>
219+
<LinearProgress color="secondary" />
220+
</Box>
221+
)}
222+
{!updating && (
223+
<React.Fragment>
224+
<Button onClick={this.handleClose}>Cancel</Button>
225+
<Button onClick={this.handleModify}>Save</Button>
226+
</React.Fragment>
227+
)}
228+
</DialogActions>
229+
</Dialog>
230+
);
231+
}
232+
}
233+
234+
export default CommandGroupDialog;

0 commit comments

Comments
 (0)