Skip to content

Commit cffcb80

Browse files
committed
added 'Add Transition' from transition table to playground
1 parent bc2fab8 commit cffcb80

File tree

8 files changed

+365
-94
lines changed

8 files changed

+365
-94
lines changed

src/components/Editor.tsx

Lines changed: 269 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { promptNewStateName } from "../utils/PromptNewStateName";
1414
import { PossibleTransitionValues } from "../consts/PossibleTransitionValues";
1515
import { StateNameMaxLength } from "../consts/StateNameMaxLength";
1616
import { PlaygroundSize } from "./interfaces/playgroundSize";
17+
import { StyledTransitionLabel } from "../features/components/playground/StyledTransitionLabel";
18+
import { MaxNumberOfStates } from "../consts/MaxNumberOfStates";
1719

1820
const Editor = () => {
1921
console.log("re rendering Editor");
@@ -97,6 +99,10 @@ const Editor = () => {
9799
const [size, setSize] = useState<PlaygroundSize>({ width: 0, height: 0 });
98100

99101
const handleAddRow = (row: RowModel) => {
102+
if (boxes.length >= MaxNumberOfStates) {
103+
alert(`Maximum ${MaxNumberOfStates} states allowed`);
104+
return;
105+
}
100106
setGridData((prev) => [...prev, row]);
101107
setGridRowId((prev) => prev + 1);
102108
console.log(
@@ -178,28 +184,54 @@ const Editor = () => {
178184
return;
179185
}
180186

181-
const previousRow = gridData.find((r) => r.id === row.id);
187+
const oldRow = gridData.find((r) => r.id === row.id);
188+
if (!oldRow) {
189+
alert("Cannot save row.");
190+
return;
191+
}
192+
182193
if (row.node.length > StateNameMaxLength) {
183194
alert(`State name cannot be more than ${StateNameMaxLength} characters.`);
184-
if (previousRow) {
185-
setGridData((prev) =>
186-
prev.map((r) => (r.id === row.id ? previousRow : r))
187-
);
195+
if (oldRow) {
196+
setGridData((prev) => prev.map((r) => (r.id === row.id ? oldRow : r)));
197+
}
198+
return;
199+
}
200+
201+
// if state name is changed AND transition values are added/updated/removed, not allowed
202+
if (
203+
oldRow.node !== row.node &&
204+
PossibleTransitionValues.some(
205+
(key) =>
206+
row[key === "^" ? "nul" : key] !== oldRow[key === "^" ? "nul" : key]
207+
)
208+
) {
209+
alert(
210+
`Cannot change state name when transition values are added/updated/removed.`
211+
);
212+
if (oldRow) {
213+
setGridData((prev) => prev.map((r) => (r.id === row.id ? oldRow : r)));
188214
}
189215
return;
190216
}
191217

218+
const nulPossibleTransitionValues = PossibleTransitionValues.map((v) =>
219+
v === "^" ? "nul" : v
220+
);
221+
let updatedGridData: RowModel[] = [];
222+
let errorWhileSavingRow = false;
192223
setGridData((prev) => {
193224
console.log("handleSaveRow prev", prev);
194225
let availableNodeValues = prev.map((r) => r.node).filter((v) => v !== "");
226+
// if (oldRow.node !== row.node)
227+
// availableNodeValues = availableNodeValues
228+
// .filter((v) => v !== oldRow.node)
229+
// .concat(row.node);
230+
195231
if (!availableNodeValues.includes(row.node))
196232
availableNodeValues.push(row.node);
197-
198233
console.log("availableNodeValues", availableNodeValues);
199234

200-
const nulPossibleTransitionValues = PossibleTransitionValues.map((v) =>
201-
v === "^" ? "nul" : v
202-
);
203235
const areTransitionValuesInvalid = nulPossibleTransitionValues.some(
204236
(key) => {
205237
const transitionValues = row[key]
@@ -217,22 +249,24 @@ const Editor = () => {
217249
", "
218250
)}`
219251
);
220-
return prev;
252+
errorWhileSavingRow = true;
253+
return prev.map((r) => (r.id === row.id ? oldRow : r));
221254
}
222255

223-
const nodeAlreadyExists = prev.find(
256+
const stateAlreadyExists = prev.find(
224257
(r) =>
225258
r.node === row.node &&
226259
r.a === row.a &&
227260
r.b === row.b &&
228261
r.nul === row.nul
229262
);
230-
if (nodeAlreadyExists) {
263+
if (stateAlreadyExists) {
231264
alert("This state value already exists. Kindly choose another value.");
265+
errorWhileSavingRow = true;
232266
return prev;
233267
}
234268

235-
return prev.map((r) =>
269+
updatedGridData = prev.map((r) =>
236270
r.id === row.id
237271
? {
238272
...r,
@@ -242,10 +276,10 @@ const Editor = () => {
242276
key === "^" ? "nul" : key,
243277
row[key === "^" ? "nul" : key]
244278
.toString()
245-
.includes(previousRow.node)
279+
.includes(oldRow.node)
246280
? row[key === "^" ? "nul" : key]
247281
.toString()
248-
.replace(previousRow.node, row.node)
282+
.replace(oldRow.node, row.node)
249283
: row[key === "^" ? "nul" : key],
250284
])
251285
),
@@ -255,41 +289,232 @@ const Editor = () => {
255289
...Object.fromEntries(
256290
PossibleTransitionValues.map((key) => [
257291
key === "^" ? "nul" : key,
258-
r[key === "^" ? "nul" : key]
259-
.toString()
260-
.includes(previousRow.node)
292+
r[key === "^" ? "nul" : key].toString().includes(oldRow.node)
261293
? r[key === "^" ? "nul" : key]
262294
.toString()
263-
.replace(previousRow.node, row.node)
295+
.replace(oldRow.node, row.node)
264296
: r[key === "^" ? "nul" : key],
265297
])
266298
),
267299
}
268300
);
301+
302+
return updatedGridData;
269303
});
270304

271-
setBoxes((prev) =>
272-
prev.map((b) => (b.id === previousRow.node ? { ...b, id: row.node } : b))
273-
);
305+
if (!errorWhileSavingRow) {
306+
setBoxes((prev) =>
307+
prev.map((b) => (b.id === oldRow.node ? { ...b, id: row.node } : b))
308+
);
274309

275-
setLines((prev) =>
276-
prev.map((l) =>
277-
l.props.start === previousRow.node && l.props.end === previousRow.node
278-
? {
279-
...l,
280-
props: {
281-
...l.props,
282-
start: row.node,
283-
end: row.node,
284-
},
310+
// if only state name is changed
311+
if (
312+
oldRow.node !== row.node &&
313+
PossibleTransitionValues.every(
314+
(key) =>
315+
row[key === "^" ? "nul" : key] === oldRow[key === "^" ? "nul" : key]
316+
)
317+
) {
318+
let updatedtransitions = lines.map((l) =>
319+
l.props.start === oldRow.node && l.props.end === oldRow.node
320+
? {
321+
...l,
322+
props: {
323+
...l.props,
324+
start: row.node,
325+
end: row.node,
326+
},
327+
}
328+
: l.props.start === oldRow.node
329+
? {
330+
...l,
331+
props: {
332+
...l.props,
333+
start: row.node,
334+
},
335+
}
336+
: l.props.end === oldRow.node
337+
? {
338+
...l,
339+
props: {
340+
...l.props,
341+
end: row.node,
342+
},
343+
}
344+
: l
345+
);
346+
console.log("updatedtransitions", updatedtransitions);
347+
setLines(updatedtransitions);
348+
} else {
349+
// if new transitions are added
350+
351+
let addedTransitions: TransitionModel[] = [];
352+
let removedTransitions: TransitionModel[] = [];
353+
354+
PossibleTransitionValues.forEach((key) => {
355+
const oldTransitionValues = oldRow[key === "^" ? "nul" : key]
356+
.toString()
357+
.split(" ")
358+
.filter((v) => v !== "");
359+
console.log("oldTransitionValues", oldTransitionValues);
360+
361+
const newTransitionValues = row[key === "^" ? "nul" : key]
362+
.toString()
363+
.split(" ")
364+
.filter((v) => v !== "");
365+
console.log("newTransitionValues", newTransitionValues);
366+
367+
const addedTransitionValues = newTransitionValues.filter(
368+
(v) => !oldTransitionValues.includes(v)
369+
);
370+
console.log("addedTransitionValues", addedTransitionValues);
371+
372+
const removedTransitionValues = oldTransitionValues.filter(
373+
(v) => !newTransitionValues.includes(v)
374+
);
375+
console.log("removedTransitionValues", removedTransitionValues);
376+
377+
addedTransitionValues.forEach((v) => {
378+
console.log("addedTransitionValues key, v: ", key, v);
379+
380+
// if transition value v is already present in the transitions array, then just update it's labels & value
381+
const transitionAlreadyExists = addedTransitions.find(
382+
(t) => t.props.start === row.node && t.props.end === v
383+
);
384+
385+
if (transitionAlreadyExists) {
386+
transitionAlreadyExists.props.labels = (
387+
<StyledTransitionLabel
388+
label={transitionAlreadyExists.props.value + key}
389+
/>
390+
);
391+
transitionAlreadyExists.props.value =
392+
transitionAlreadyExists.props.value + key;
393+
} else {
394+
const isSelfTransition = v === row.node;
395+
const newLine: TransitionModel = {
396+
props: {
397+
start: row.node,
398+
end: v,
399+
labels: <StyledTransitionLabel label={key} />,
400+
value: key,
401+
animateDrawing: true,
402+
_extendSVGcanvas: isSelfTransition ? 25 : 0,
403+
_cpx1Offset: isSelfTransition ? -50 : 0,
404+
_cpy1Offset: isSelfTransition ? -50 : 0,
405+
_cpx2Offset: isSelfTransition ? 50 : 0,
406+
_cpy2Offset: isSelfTransition ? -50 : 0,
407+
},
408+
menuWindowOpened: false,
409+
};
410+
addedTransitions.push(newLine);
285411
}
286-
: l.props.start === previousRow.node
287-
? { ...l, props: { ...l.props, start: row.node } }
288-
: l.props.end === previousRow.node
289-
? { ...l, props: { ...l.props, end: row.node } }
290-
: l
291-
)
292-
);
412+
});
413+
console.log("addedTransitions", addedTransitions);
414+
415+
removedTransitionValues.forEach((v) => {
416+
console.log("removedTransitionValues key, v: ", key, v);
417+
const removedTransition = lines.find(
418+
(l) => l.props.start === row.node && l.props.end === v
419+
);
420+
421+
// if removed transition's label (value) is of length 1, then remove the transition
422+
if (removedTransition.props.value.length === 1) {
423+
removedTransitions.push(removedTransition);
424+
} else {
425+
// else just update the transition's label & value
426+
removedTransition.props.labels = (
427+
<StyledTransitionLabel
428+
label={removedTransition.props.value.replace(key, "")}
429+
/>
430+
);
431+
removedTransition.props.value =
432+
removedTransition.props.value.replace(key, "");
433+
}
434+
});
435+
console.log("removedTransitions", removedTransitions);
436+
});
437+
438+
setLines((prev) => {
439+
// update removedTransitions's labels && value if it's already present
440+
const updatedRemovedTransitions = prev.map((l) =>
441+
removedTransitions.find(
442+
(t) => t.props.start === l.props.start && t.props.end === l.props.end
443+
)
444+
? {
445+
...l,
446+
props: {
447+
...l.props,
448+
labels: (
449+
<StyledTransitionLabel
450+
label={
451+
removedTransitions.find(
452+
(t) =>
453+
t.props.start === l.props.start &&
454+
t.props.end === l.props.end
455+
)?.props.value
456+
}
457+
/>
458+
),
459+
value:
460+
removedTransitions.find(
461+
(t) =>
462+
t.props.start === l.props.start &&
463+
t.props.end === l.props.end
464+
)?.props.value,
465+
},
466+
}
467+
: l
468+
);
469+
470+
471+
// const updatedRemovedTransitions = prev.filter(
472+
// (l) =>
473+
// !removedTransitions.find(
474+
// (r) =>
475+
// r.props.start === l.props.start && r.props.end === l.props.end
476+
// )
477+
// );
478+
console.log("updatedRemovedTransitions", updatedRemovedTransitions);
479+
480+
// update addedTransitions's labels & value if it's are already present
481+
const updatedAddedTransitions = addedTransitions.map((a) => {
482+
const transitionAlreadyExists = prev.find(
483+
(p) =>
484+
p.props.start === a.props.start && p.props.end === a.props.end
485+
);
486+
console.log(
487+
"transitionAlreadyExists.props.value, a.props.value:",
488+
transitionAlreadyExists?.props.value,
489+
a.props.value
490+
);
491+
if (
492+
transitionAlreadyExists &&
493+
transitionAlreadyExists.props.value !== a.props.value
494+
) {
495+
return {
496+
...transitionAlreadyExists,
497+
props: {
498+
...transitionAlreadyExists.props,
499+
labels: (
500+
<StyledTransitionLabel
501+
label={
502+
transitionAlreadyExists.props.value + a.props.value
503+
}
504+
/>
505+
),
506+
value: transitionAlreadyExists.props.value + a.props.value,
507+
},
508+
};
509+
}
510+
return a;
511+
});
512+
console.log("updatedAddedTransitions", updatedAddedTransitions);
513+
514+
return [...updatedRemovedTransitions, ...updatedAddedTransitions];
515+
});
516+
}
517+
}
293518
};
294519

295520
const toggleInitialState = (row: RowModel) => {
@@ -367,8 +592,11 @@ const Editor = () => {
367592

368593
const handleDropDynamic = (e: any) => {
369594
console.log("handleDropDynamic", e);
370-
// let l = boxes.length;
371-
// while (checkExsitence("q" + l)) l++;
595+
if (boxes.length >= MaxNumberOfStates) {
596+
alert(`Maximum ${MaxNumberOfStates} states allowed.`);
597+
return;
598+
}
599+
372600
let { x, y } = e.target.getBoundingClientRect();
373601
const stateName = promptNewStateName(boxes, `q${gridRowId}`);
374602
if (stateName) {

src/consts/MaxNumberOfStates.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const MaxNumberOfStates = 20; // cannot be greater than 100 because DataGrid accepts maximum of 100 rows
File renamed without changes.

0 commit comments

Comments
 (0)