Skip to content

Commit d191e99

Browse files
committed
added a limit to test string length and possible input characters
1 parent 12e1e20 commit d191e99

File tree

3 files changed

+147
-120
lines changed

3 files changed

+147
-120
lines changed

src/components/Editor.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { createContext, useState } from "react";
22
import {
33
Alert,
4-
AlertTitle,
54
Box,
65
Button,
76
Dialog,
@@ -217,12 +216,17 @@ export const Editor = () => {
217216
return;
218217
}
219218

219+
const oldRow = rows.find((r) => r.id === row.id);
220+
220221
if (PossibleTransitionValues.includes(row.state)) {
221222
setAlertMessage(
222223
`State name cannot be one of the following: ${PossibleTransitionValues.join(
223224
", "
224225
)}`
225226
);
227+
228+
// reset this row to old row
229+
setRows((prev) => prev.map((r) => (r.id === row.id ? oldRow : r)));
226230
return;
227231
}
228232

@@ -238,7 +242,6 @@ export const Editor = () => {
238242
).join(" "))
239243
);
240244

241-
const oldRow = rows.find((r) => r.id === row.id);
242245
if (!oldRow) {
243246
setAlertMessage("Cannot save row.");
244247
return;
@@ -251,7 +254,6 @@ export const Editor = () => {
251254

252255
// reset this row to old row
253256
setRows((prev) => prev.map((r) => (r.id === row.id ? oldRow : r)));
254-
255257
return;
256258
}
257259

@@ -269,7 +271,6 @@ export const Editor = () => {
269271

270272
// reset this row to old row
271273
setRows((prev) => prev.map((r) => (r.id === row.id ? oldRow : r)));
272-
273274
return;
274275
}
275276

@@ -318,7 +319,7 @@ export const Editor = () => {
318319

319320
if (stateAlreadyExists) {
320321
setAlertMessage(
321-
"This state value already exists. Kindly choose another value."
322+
"This state name already exists. Kindly choose another name."
322323
);
323324
errorWhileSavingRow = true;
324325
return prev.map((r) => (r.id === row.id ? oldRow : r));
@@ -577,12 +578,12 @@ export const Editor = () => {
577578

578579
const handleStateNameDialogValue = (e: any) => {
579580
if (!stateNameDialogValue)
580-
setStateNameDialogError("Name cannot be empty, choose another one: ");
581+
setStateNameDialogError("Name cannot be empty, choose another one.");
581582
else if (
582583
stateNameDialogValue &&
583584
[...states].map((s) => s.id).includes(stateNameDialogValue)
584585
)
585-
setStateNameDialogError("Name already taken, choose another one: ");
586+
setStateNameDialogError("Name already taken, choose another one.");
586587
else if (stateNameDialogValue.length > StateNameMaxLength)
587588
setStateNameDialogError(
588589
`State name cannot be more than ${StateNameMaxLength} characters.`
@@ -676,7 +677,7 @@ export const Editor = () => {
676677
<TextField
677678
autoFocus
678679
margin="dense"
679-
id="testString"
680+
id="newStateNameDialog"
680681
label="State Name"
681682
type="text"
682683
fullWidth

src/consts/TestStringMaxLength.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const TestStringMaxLength = 100;

src/features/TestAString.tsx

Lines changed: 137 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,9 @@ import ReplayRoundedIcon from "@mui/icons-material/ReplayRounded";
2626
import { ToolsPlaygroundProps } from "./components/tools/props/PlaygroundProps";
2727
import { DraggableStateModel, TransitionModel } from "../models";
2828
import { DataContext } from "../components/Editor";
29-
import {
30-
startingStateColor,
31-
stateSelectedColor,
32-
transitionColor,
33-
transitionHoverColor,
34-
} from "../consts/Colors";
29+
import { startingStateColor, stateSelectedColor } from "../consts/Colors";
30+
import { PossibleTransitionValues } from "../consts/PossibleTransitionValues";
31+
import { TestStringMaxLength } from "../consts/TestStringMaxLength";
3532

3633
const TestAString = (props: TestAStringProps) => {
3734
console.log("re rendering TestAString: props");
@@ -63,6 +60,7 @@ const TestAString = (props: TestAStringProps) => {
6360
const [highlightedTransitions, setHighlightedTransitions] = useState<
6461
TransitionModel[]
6562
>([]);
63+
const [dialogError, setDialogError] = useState("");
6664

6765
useEffect(() => {
6866
if (dataContext) {
@@ -221,11 +219,34 @@ const TestAString = (props: TestAStringProps) => {
221219
};
222220

223221
const handleChange = (value: string) => {
224-
let appendedValue = value.split("").join("^");
225-
if (appendedValue?.length > 0) {
226-
appendedValue = "^" + appendedValue + "^";
222+
if (value.length <= TestStringMaxLength) {
223+
let appendedValue = value.split("").join("^");
224+
if (appendedValue?.length > 0) {
225+
appendedValue = "^" + appendedValue + "^";
226+
}
227+
setTestString(appendedValue);
228+
} else
229+
setDialogError(
230+
`Test string cannot be more than ${TestStringMaxLength} characters.`
231+
);
232+
};
233+
234+
const handleSubmit = () => {
235+
if (testString === "") setDialogError("Please enter a valid string.");
236+
else if (testString.includes("^^"))
237+
setDialogError("Please remove ^ from the string.");
238+
else if (
239+
!testString.split("").every((c) => PossibleTransitionValues.includes(c))
240+
)
241+
setDialogError(
242+
`Please enter a valid string from following characters ${PossibleTransitionValues.filter(
243+
(v) => v !== "^"
244+
).join(", ")}`
245+
);
246+
else {
247+
setDialogError("none");
248+
handleClose();
227249
}
228-
setTestString(appendedValue);
229250
};
230251

231252
const playgroundProps: ToolsPlaygroundProps = {
@@ -238,7 +259,7 @@ const TestAString = (props: TestAStringProps) => {
238259
};
239260
}),
240261
currentStates: statesToHighlight.map((state) => `${state}ts`),
241-
stateSize: dataContext.stateSize
262+
stateSize: dataContext.stateSize,
242263
};
243264

244265
return (
@@ -247,7 +268,9 @@ const TestAString = (props: TestAStringProps) => {
247268
<DialogTitle>Test a string</DialogTitle>
248269
<DialogContent>
249270
<DialogContentText>
250-
Enter a string to test if it is accepted by the Automaton.
271+
{dialogError === "" || dialogError === "none"
272+
? "Enter a string to test if it is accepted by the Automaton."
273+
: dialogError}
251274
</DialogContentText>
252275
<TextField
253276
autoFocus
@@ -263,111 +286,113 @@ const TestAString = (props: TestAStringProps) => {
263286
</DialogContent>
264287
<DialogActions>
265288
<Button onClick={handleClose}>Cancel</Button>
266-
<Button onClick={handleClose}>Ok</Button>
289+
<Button onClick={handleSubmit}>Ok</Button>
267290
</DialogActions>
268291
</Dialog>
269292

270-
<Box sx={{ flexGrow: 1, m: 1, mt: 5 }}>
271-
<Typography
272-
variant="h5"
273-
component="div"
274-
gutterBottom
275-
align="center"
276-
fontWeight={"bold"}
277-
bgcolor={stateSelectedColor}
278-
>
279-
Test a String
280-
</Typography>
281-
282-
<Grid
283-
container
284-
columnSpacing={{
285-
xs: 1,
286-
sm: 2,
287-
md: 3,
288-
}}
289-
>
290-
<Grid item xs={12} alignItems={"center"}>
291-
<ButtonGroup
292-
disableElevation
293-
fullWidth
294-
variant="outlined"
295-
size="large"
296-
>
297-
{testString
298-
.replaceAll("^", "")
299-
.split("")
300-
.map((char, index) => (
301-
<TextField
302-
key={index}
303-
id={`testString${index}`}
304-
value={char}
305-
variant="standard"
306-
InputProps={{
307-
readOnly: true,
308-
sx: {
309-
textAlignLast: "center",
310-
},
311-
}}
312-
sx={{
313-
backgroundColor:
314-
Math.floor((testStringIndex - 1) / 2) === index
315-
? startingStateColor
316-
: "inherit",
317-
flexDirection: "inherit",
318-
borderRadius: "20px",
319-
border: `1px solid ${stateSelectedColor}`,
320-
borderWidth: "0 1px 0 1px",
321-
}}
322-
/>
323-
))}
324-
325-
<FormControl fullWidth>
326-
<InputLabel id="delay-select-label">Delay</InputLabel>
327-
<Select
328-
labelId="delay-select-label"
329-
id="delay-select"
330-
value={duration.toString()}
331-
label="Delay"
332-
onChange={handleDurationChange}
333-
>
334-
{AnimationDurationOptions.map((option) => (
335-
<MenuItem key={option} value={option}>
336-
{option}
337-
</MenuItem>
338-
))}
339-
</Select>
340-
</FormControl>
341-
342-
<Button
343-
onClick={handleAnimation}
344-
startIcon={
345-
isPlaying ? (
346-
<PauseRoundedIcon />
347-
) : isComplete ? (
348-
<ReplayRoundedIcon />
349-
) : (
350-
<PlayArrowRoundedIcon />
351-
)
352-
}
293+
{dialogError === "none" && (
294+
<Box sx={{ flexGrow: 1, m: 1, mt: 5 }}>
295+
<Typography
296+
variant="h5"
297+
component="div"
298+
gutterBottom
299+
align="center"
300+
fontWeight={"bold"}
301+
bgcolor={stateSelectedColor}
302+
>
303+
Test a String
304+
</Typography>
305+
306+
<Grid
307+
container
308+
columnSpacing={{
309+
xs: 1,
310+
sm: 2,
311+
md: 3,
312+
}}
313+
>
314+
<Grid item xs={12} alignItems={"center"}>
315+
<ButtonGroup
316+
disableElevation
317+
fullWidth
318+
variant="outlined"
319+
size="large"
353320
>
354-
{isPlaying ? "Pause" : isComplete ? "Replay" : "Play"}
355-
</Button>
356-
<Button
357-
variant={isComplete ? "contained" : "outlined"}
358-
onClick={showNextRow}
359-
disabled={isReady}
360-
>
361-
{isComplete ? "Complete" : "Next"}
362-
</Button>
363-
</ButtonGroup>
364-
</Grid>
365-
{/* Playground grid */}
366-
<Grid item xs={12}>
367-
<ToolsPlayground {...playgroundProps} />
321+
{testString
322+
.replaceAll("^", "")
323+
.split("")
324+
.map((char, index) => (
325+
<TextField
326+
key={index}
327+
id={`testString${index}`}
328+
value={char}
329+
variant="standard"
330+
InputProps={{
331+
readOnly: true,
332+
sx: {
333+
textAlignLast: "center",
334+
},
335+
}}
336+
sx={{
337+
backgroundColor:
338+
Math.floor((testStringIndex - 1) / 2) === index
339+
? startingStateColor
340+
: "inherit",
341+
flexDirection: "inherit",
342+
borderRadius: "20px",
343+
border: `1px solid ${stateSelectedColor}`,
344+
borderWidth: "0 1px 0 1px",
345+
}}
346+
/>
347+
))}
348+
349+
<FormControl fullWidth>
350+
<InputLabel id="delay-select-label">Delay</InputLabel>
351+
<Select
352+
labelId="delay-select-label"
353+
id="delay-select"
354+
value={duration.toString()}
355+
label="Delay"
356+
onChange={handleDurationChange}
357+
>
358+
{AnimationDurationOptions.map((option) => (
359+
<MenuItem key={option} value={option}>
360+
{option}
361+
</MenuItem>
362+
))}
363+
</Select>
364+
</FormControl>
365+
366+
<Button
367+
onClick={handleAnimation}
368+
startIcon={
369+
isPlaying ? (
370+
<PauseRoundedIcon />
371+
) : isComplete ? (
372+
<ReplayRoundedIcon />
373+
) : (
374+
<PlayArrowRoundedIcon />
375+
)
376+
}
377+
>
378+
{isPlaying ? "Pause" : isComplete ? "Replay" : "Play"}
379+
</Button>
380+
<Button
381+
variant={isComplete ? "contained" : "outlined"}
382+
onClick={showNextRow}
383+
disabled={isReady}
384+
>
385+
{isComplete ? "Complete" : "Next"}
386+
</Button>
387+
</ButtonGroup>
388+
</Grid>
389+
{/* Playground grid */}
390+
<Grid item xs={12}>
391+
<ToolsPlayground {...playgroundProps} />
392+
</Grid>
368393
</Grid>
369-
</Grid>
370-
</Box>
394+
</Box>
395+
)}
371396
</>
372397
);
373398
};

0 commit comments

Comments
 (0)