Allow editing cardinality 'many' label (#559)

This commit is contained in:
1ilit
2025-08-23 21:47:05 +04:00
committed by GitHub
parent 3eac4c342a
commit 1eb4e298e9
3 changed files with 95 additions and 58 deletions

View File

@@ -1,10 +1,5 @@
import { useMemo, useRef } from "react"; import { useMemo, useRef, useState, useEffect } from "react";
import { import { Cardinality, ObjectType, Tab } from "../../data/constants";
Cardinality,
darkBgTheme,
ObjectType,
Tab,
} from "../../data/constants";
import { calcPath } from "../../utils/calcPath"; import { calcPath } from "../../utils/calcPath";
import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks"; import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -46,13 +41,13 @@ export default function Relationship({ data }) {
// the translated values are to ensure backwards compatibility // the translated values are to ensure backwards compatibility
case t(Cardinality.MANY_TO_ONE): case t(Cardinality.MANY_TO_ONE):
case Cardinality.MANY_TO_ONE: case Cardinality.MANY_TO_ONE:
cardinalityStart = "n"; cardinalityStart = data.manyLabel || "n";
cardinalityEnd = "1"; cardinalityEnd = "1";
break; break;
case t(Cardinality.ONE_TO_MANY): case t(Cardinality.ONE_TO_MANY):
case Cardinality.ONE_TO_MANY: case Cardinality.ONE_TO_MANY:
cardinalityStart = "1"; cardinalityStart = "1";
cardinalityEnd = "n"; cardinalityEnd = data.manyLabel || "n";
break; break;
case t(Cardinality.ONE_TO_ONE): case t(Cardinality.ONE_TO_ONE):
case Cardinality.ONE_TO_ONE: case Cardinality.ONE_TO_ONE:
@@ -128,63 +123,30 @@ export default function Relationship({ data }) {
cursor="pointer" cursor="pointer"
/> />
{settings.showRelationshipLabels && ( {settings.showRelationshipLabels && (
<> <text
<rect x={labelX}
x={labelX - 2} y={labelY}
y={labelY - labelFontSize} fill={settings.mode === "dark" ? "lightgrey" : "#333"}
fill={settings.mode === "dark" ? darkBgTheme : "white"} fontSize={labelFontSize}
width={labelWidth + 4} fontWeight={500}
height={labelHeight} ref={labelRef}
/> className="group-hover:fill-sky-700"
<text >
x={labelX} {data.name}
y={labelY} </text>
fill={settings.mode === "dark" ? "lightgrey" : "#333"}
fontSize={labelFontSize}
fontWeight={500}
ref={labelRef}
className="group-hover:fill-sky-700"
>
{data.name}
</text>
</>
)} )}
{pathRef.current && settings.showCardinality && ( {pathRef.current && settings.showCardinality && (
<> <>
<circle <CardinalityLabel
cx={cardinalityStartX}
cy={cardinalityStartY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
x={cardinalityStartX} x={cardinalityStartX}
y={cardinalityStartY} y={cardinalityStartY}
fill="white" text={cardinalityStart}
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityStart}
</text>
<circle
cx={cardinalityEndX}
cy={cardinalityEndY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/> />
<text <CardinalityLabel
x={cardinalityEndX} x={cardinalityEndX}
y={cardinalityEndY} y={cardinalityEndY}
fill="white" text={cardinalityEnd}
strokeWidth="0.5" />
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityEnd}
</text>
</> </>
)} )}
</g> </g>
@@ -212,3 +174,41 @@ export default function Relationship({ data }) {
</> </>
); );
} }
function CardinalityLabel({ x, y, text, r = 12, padding = 14 }) {
const [textWidth, setTextWidth] = useState(0);
const textRef = useRef(null);
useEffect(() => {
if (textRef.current) {
const bbox = textRef.current.getBBox();
setTextWidth(bbox.width);
}
}, [text]);
return (
<g>
<rect
x={x - textWidth / 2 - padding / 2}
y={y - r}
rx={r}
ry={r}
width={textWidth + padding}
height={r * 2}
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
ref={textRef}
x={x}
y={y}
fill="white"
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{text}
</text>
</g>
);
}

View File

@@ -223,6 +223,41 @@ export default function RelationshipInfo({ data }) {
className="w-full" className="w-full"
onChange={changeCardinality} onChange={changeCardinality}
/> />
{data.cardinality !== Cardinality.ONE_TO_ONE && (
<>
<div className="text-md font-semibold break-keep mt-2">
{t("many_side_label")}:
</div>
<Input
value={data.manyLabel}
placeholder={t("label")}
onChange={(value) => updateRelationship(data.id, { manyLabel: value })}
onFocus={(e) => setEditField({ manyLabel: e.target.value })}
defaultValue="n"
onBlur={(e) => {
if (e.target.value === editField.manyLabel) return;
setUndoStack((prev) => [
...prev,
{
action: Action.EDIT,
element: ObjectType.RELATIONSHIP,
component: "self",
rid: data.id,
undo: editField,
redo: { manyLabel: e.target.value },
message: t("edit_relationship", {
refName: e.target.value,
extra: "[manyLabel]",
}),
},
]);
setRedoStack([]);
}}
/>
</>
)}
<Row gutter={6} className="my-3"> <Row gutter={6} className="my-3">
<Col span={12}> <Col span={12}>
<div className="font-semibold">{t("on_update")}: </div> <div className="font-semibold">{t("on_update")}: </div>

View File

@@ -256,6 +256,8 @@ const en = {
export_saved_data: "Export saved data", export_saved_data: "Export saved data",
dbml_view: "DBML view", dbml_view: "DBML view",
tab_view: "Tab view", tab_view: "Tab view",
label: "Label",
many_side_label: "Many(n) side label",
}, },
}; };