1 or *). E.g., (0,5), (1,*)"
@@ -609,6 +631,8 @@ export default function RelationshipInfo({ data }) {
/>
Format: (x,y) where x is 0 or 1, and y is greater than 1 or *
+
+ Press Enter to apply, Escape to cancel
+
+
+
+
+ setChangeCardinalityModal((prev) => ({
+ ...prev,
+ newCardinality: value,
+ }))
+ }
+ placeholder={"e.g., (1,n)"}
+ onEnterPress={handleChangeCardinalityConfirm}
+ />
+
+ {/* ADD THIS SECTION FOR THE LEGEND */}
+
+
Format: (x,y) where x is 0 or 1, and y is n, *, or a number.
+
+
+
+
Date: Mon, 6 Oct 2025 08:01:26 -0600
Subject: [PATCH 5/6] Fix: Prevent leading zeros in custom cardinality
validation
---
src/components/EditorCanvas/Canvas.jsx | 38 ++++++++++++++++---
.../RelationshipsTab/RelationshipInfo.jsx | 9 +++++
src/data/constants.js | 14 +++----
3 files changed, 49 insertions(+), 12 deletions(-)
diff --git a/src/components/EditorCanvas/Canvas.jsx b/src/components/EditorCanvas/Canvas.jsx
index e8e7cd444..69f5c27de 100644
--- a/src/components/EditorCanvas/Canvas.jsx
+++ b/src/components/EditorCanvas/Canvas.jsx
@@ -1025,16 +1025,44 @@ export default function Canvas() {
};
const validateCustomCardinality = (cardinality) => {
- const regex = /^\((0|1),(n|\*|\d+)\)$/;
- if (regex.test(cardinality)) {
- return { valid: true };
- } else {
+ const match = cardinality.match(/^\(\s*(\d+)\s*,\s*(\d+|\*)\s*\)$/);
+ if (!match) {
+ return {
+ valid: false,
+ message: "Invalid format. Use (x,y) where x is 0 or 1, and y is greater than 1 or *",
+ };
+ }
+
+ const first = parseInt(match[1]);
+ const second = match[2];
+
+ // First coordinate must be 0 or 1
+ if (first !== 0 && first !== 1) {
return {
valid: false,
- message: "Invalid format. Use (0,n), (1,*), or (0,10).",
+ message: "First coordinate must be 0 or 1",
};
}
+
+ // Second coordinate must be * or a number greater than 1
+ if (second !== "*") {
+ if (/^0\d+$/.test(second)) {
+ return {
+ valid: false,
+ message: "Second coordinate must not have leading zeros.",
+ };
+ }
+ const secondNum = parseInt(second);
+ if (isNaN(secondNum) || secondNum < 2) {
+ return {
+ valid: false,
+ message: "Second coordinate must be greater than 1 or *",
+ };
+ }
+ }
+
+ return { valid: true };
};
const handleDeleteRelationship = () => {
diff --git a/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx b/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
index 7f512d2be..4faf7a251 100644
--- a/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
+++ b/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
@@ -296,6 +296,15 @@ export default function RelationshipInfo({ data }) {
// Second coordinate must be * or a number greater than 1
if (second !== "*") {
+ if (/^0\d+$/.test(second)) {
+ return {
+ valid: false,
+ message: t(
+ "cardinality_second_leading_zero_error",
+ "Second coordinate must not have leading zeros.",
+ ),
+ };
+ }
const secondNum = parseInt(second);
if (isNaN(secondNum) || secondNum < 2) {
return {
diff --git a/src/data/constants.js b/src/data/constants.js
index d45a1dc9f..d9b9812b6 100644
--- a/src/data/constants.js
+++ b/src/data/constants.js
@@ -37,19 +37,19 @@ export const RelationshipType = {
export const RelationshipCardinalities = {
[RelationshipType.ONE_TO_ONE]: [
- { value: "0,1", label: "(0,1)" },
- { value: "1,1", label: "(1,1)" },
+ {value: "0,1", label: "(0,1)"},
+ {value: "1,1", label: "(1,1)"},
],
[RelationshipType.ONE_TO_MANY]: [
- { value: "0,*", label: "(0,*)" },
- { value: "1,*", label: "(1,*)" },
- { value: "custom", label: "Custom..." },
+ {value: "0,*", label: "(0,*)"},
+ {value: "1,*", label: "(1,*)"},
+ {value: "custom", label: "Custom..."},
],
};
export const ParentCardinality = {
- DEFAULT: { value: "1,1", label: "(1,1)" },
- NULLEABLE: { value: "0,1", label: "(0,1)" },
+ DEFAULT: {value: "1,1", label: "(1,1)"},
+ NULLEABLE: {value: "0,1", label: "(0,1)"},
};
export const Notation = {
From 2440f80d0ca84a6c4400f644fcd4c9f9a9ddac61 Mon Sep 17 00:00:00 2001
From: lethalSopaper <2bluisugartechea@gmail.com>
Date: Wed, 8 Oct 2025 07:32:03 -0600
Subject: [PATCH 6/6] Fix: allowing leading zeroes but normalizing when entered
---
src/components/EditorCanvas/Canvas.jsx | 20 +++++++++-------
.../RelationshipsTab/RelationshipInfo.jsx | 24 ++++++++++---------
2 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/src/components/EditorCanvas/Canvas.jsx b/src/components/EditorCanvas/Canvas.jsx
index 69f5c27de..ac66fc56c 100644
--- a/src/components/EditorCanvas/Canvas.jsx
+++ b/src/components/EditorCanvas/Canvas.jsx
@@ -516,7 +516,8 @@ export default function Canvas() {
return;
}
- updateRelationship(relationshipId, { cardinality: trimmedCardinality });
+ const normalizedCardinality = normalizeCardinality(trimmedCardinality);
+ updateRelationship(relationshipId, { cardinality: normalizedCardinality });
setChangeCardinalityModal({
visible: false,
@@ -1025,7 +1026,6 @@ export default function Canvas() {
};
const validateCustomCardinality = (cardinality) => {
-
const match = cardinality.match(/^\(\s*(\d+)\s*,\s*(\d+|\*)\s*\)$/);
if (!match) {
return {
@@ -1047,12 +1047,6 @@ export default function Canvas() {
// Second coordinate must be * or a number greater than 1
if (second !== "*") {
- if (/^0\d+$/.test(second)) {
- return {
- valid: false,
- message: "Second coordinate must not have leading zeros.",
- };
- }
const secondNum = parseInt(second);
if (isNaN(secondNum) || secondNum < 2) {
return {
@@ -1065,6 +1059,16 @@ export default function Canvas() {
return { valid: true };
};
+ const normalizeCardinality = (cardinality) => {
+ const match = cardinality.match(/^\(\s*(\d+)\s*,\s*(\d+|\*)\s*\)$/);
+ if (!match) return cardinality;
+
+ const first = parseInt(match[1]);
+ const second = match[2] === "*" ? "*" : parseInt(match[2]).toString();
+
+ return `(${first},${second})`;
+ };
+
const handleDeleteRelationship = () => {
if (relationshipContextMenu.relationshipId !== null) {
deleteRelationship(relationshipContextMenu.relationshipId);
diff --git a/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx b/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
index 4faf7a251..b35e03a6e 100644
--- a/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
+++ b/src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx
@@ -296,15 +296,6 @@ export default function RelationshipInfo({ data }) {
// Second coordinate must be * or a number greater than 1
if (second !== "*") {
- if (/^0\d+$/.test(second)) {
- return {
- valid: false,
- message: t(
- "cardinality_second_leading_zero_error",
- "Second coordinate must not have leading zeros.",
- ),
- };
- }
const secondNum = parseInt(second);
if (isNaN(secondNum) || secondNum < 2) {
return {
@@ -320,6 +311,16 @@ export default function RelationshipInfo({ data }) {
return { valid: true };
};
+ const normalizeCardinality = (cardinality) => {
+ const match = cardinality.match(/^\(\s*(\d+)\s*,\s*(\d+|\*)\s*\)$/);
+ if (!match) return cardinality;
+
+ const first = parseInt(match[1]);
+ const second = match[2] === "*" ? "*" : parseInt(match[2]).toString();
+
+ return `(${first},${second})`;
+ };
+
const applyCustomCardinality = () => {
const trimmedCardinality = customCardinality.trim();
if (trimmedCardinality === "") {
@@ -333,13 +334,14 @@ export default function RelationshipInfo({ data }) {
return;
}
+ const normalizedCardinality = normalizeCardinality(trimmedCardinality);
const timestamp = Date.now();
pushUndo({
action: Action.EDIT,
element: ObjectType.RELATIONSHIP,
rid: data.id,
undo: { cardinality: data.cardinality },
- redo: { cardinality: trimmedCardinality },
+ redo: { cardinality: normalizedCardinality },
message: t("edit_relationship", {
refName: data.name,
extra: `[cardinality-${timestamp}]`,
@@ -347,7 +349,7 @@ export default function RelationshipInfo({ data }) {
});
setRelationships((prev) =>
prev.map((e, idx) =>
- idx === data.id ? { ...e, cardinality: trimmedCardinality } : e,
+ idx === data.id ? { ...e, cardinality: normalizedCardinality } : e,
),
);
setCustomCardinality("");