Skip to content

Commit 1eb4e29

Browse files
authored
Allow editing cardinality 'many' label (#559)
1 parent 3eac4c3 commit 1eb4e29

File tree

3 files changed

+95
-58
lines changed

3 files changed

+95
-58
lines changed

src/components/EditorCanvas/Relationship.jsx

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import { useMemo, useRef } from "react";
2-
import {
3-
Cardinality,
4-
darkBgTheme,
5-
ObjectType,
6-
Tab,
7-
} from "../../data/constants";
1+
import { useMemo, useRef, useState, useEffect } from "react";
2+
import { Cardinality, ObjectType, Tab } from "../../data/constants";
83
import { calcPath } from "../../utils/calcPath";
94
import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks";
105
import { useTranslation } from "react-i18next";
@@ -46,13 +41,13 @@ export default function Relationship({ data }) {
4641
// the translated values are to ensure backwards compatibility
4742
case t(Cardinality.MANY_TO_ONE):
4843
case Cardinality.MANY_TO_ONE:
49-
cardinalityStart = "n";
44+
cardinalityStart = data.manyLabel || "n";
5045
cardinalityEnd = "1";
5146
break;
5247
case t(Cardinality.ONE_TO_MANY):
5348
case Cardinality.ONE_TO_MANY:
5449
cardinalityStart = "1";
55-
cardinalityEnd = "n";
50+
cardinalityEnd = data.manyLabel || "n";
5651
break;
5752
case t(Cardinality.ONE_TO_ONE):
5853
case Cardinality.ONE_TO_ONE:
@@ -128,63 +123,30 @@ export default function Relationship({ data }) {
128123
cursor="pointer"
129124
/>
130125
{settings.showRelationshipLabels && (
131-
<>
132-
<rect
133-
x={labelX - 2}
134-
y={labelY - labelFontSize}
135-
fill={settings.mode === "dark" ? darkBgTheme : "white"}
136-
width={labelWidth + 4}
137-
height={labelHeight}
138-
/>
139-
<text
140-
x={labelX}
141-
y={labelY}
142-
fill={settings.mode === "dark" ? "lightgrey" : "#333"}
143-
fontSize={labelFontSize}
144-
fontWeight={500}
145-
ref={labelRef}
146-
className="group-hover:fill-sky-700"
147-
>
148-
{data.name}
149-
</text>
150-
</>
126+
<text
127+
x={labelX}
128+
y={labelY}
129+
fill={settings.mode === "dark" ? "lightgrey" : "#333"}
130+
fontSize={labelFontSize}
131+
fontWeight={500}
132+
ref={labelRef}
133+
className="group-hover:fill-sky-700"
134+
>
135+
{data.name}
136+
</text>
151137
)}
152138
{pathRef.current && settings.showCardinality && (
153139
<>
154-
<circle
155-
cx={cardinalityStartX}
156-
cy={cardinalityStartY}
157-
r="12"
158-
fill="grey"
159-
className="group-hover:fill-sky-700"
160-
/>
161-
<text
140+
<CardinalityLabel
162141
x={cardinalityStartX}
163142
y={cardinalityStartY}
164-
fill="white"
165-
strokeWidth="0.5"
166-
textAnchor="middle"
167-
alignmentBaseline="middle"
168-
>
169-
{cardinalityStart}
170-
</text>
171-
<circle
172-
cx={cardinalityEndX}
173-
cy={cardinalityEndY}
174-
r="12"
175-
fill="grey"
176-
className="group-hover:fill-sky-700"
143+
text={cardinalityStart}
177144
/>
178-
<text
145+
<CardinalityLabel
179146
x={cardinalityEndX}
180147
y={cardinalityEndY}
181-
fill="white"
182-
strokeWidth="0.5"
183-
textAnchor="middle"
184-
alignmentBaseline="middle"
185-
>
186-
{cardinalityEnd}
187-
</text>
148+
text={cardinalityEnd}
149+
/>
188150
</>
189151
)}
190152
</g>
@@ -212,3 +174,41 @@ export default function Relationship({ data }) {
212174
</>
213175
);
214176
}
177+
178+
function CardinalityLabel({ x, y, text, r = 12, padding = 14 }) {
179+
const [textWidth, setTextWidth] = useState(0);
180+
const textRef = useRef(null);
181+
182+
useEffect(() => {
183+
if (textRef.current) {
184+
const bbox = textRef.current.getBBox();
185+
setTextWidth(bbox.width);
186+
}
187+
}, [text]);
188+
189+
return (
190+
<g>
191+
<rect
192+
x={x - textWidth / 2 - padding / 2}
193+
y={y - r}
194+
rx={r}
195+
ry={r}
196+
width={textWidth + padding}
197+
height={r * 2}
198+
fill="grey"
199+
className="group-hover:fill-sky-700"
200+
/>
201+
<text
202+
ref={textRef}
203+
x={x}
204+
y={y}
205+
fill="white"
206+
strokeWidth="0.5"
207+
textAnchor="middle"
208+
alignmentBaseline="middle"
209+
>
210+
{text}
211+
</text>
212+
</g>
213+
);
214+
}

src/components/EditorSidePanel/RelationshipsTab/RelationshipInfo.jsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,41 @@ export default function RelationshipInfo({ data }) {
223223
className="w-full"
224224
onChange={changeCardinality}
225225
/>
226+
227+
{data.cardinality !== Cardinality.ONE_TO_ONE && (
228+
<>
229+
<div className="text-md font-semibold break-keep mt-2">
230+
{t("many_side_label")}:
231+
</div>
232+
<Input
233+
value={data.manyLabel}
234+
placeholder={t("label")}
235+
onChange={(value) => updateRelationship(data.id, { manyLabel: value })}
236+
onFocus={(e) => setEditField({ manyLabel: e.target.value })}
237+
defaultValue="n"
238+
onBlur={(e) => {
239+
if (e.target.value === editField.manyLabel) return;
240+
setUndoStack((prev) => [
241+
...prev,
242+
{
243+
action: Action.EDIT,
244+
element: ObjectType.RELATIONSHIP,
245+
component: "self",
246+
rid: data.id,
247+
undo: editField,
248+
redo: { manyLabel: e.target.value },
249+
message: t("edit_relationship", {
250+
refName: e.target.value,
251+
extra: "[manyLabel]",
252+
}),
253+
},
254+
]);
255+
setRedoStack([]);
256+
}}
257+
/>
258+
</>
259+
)}
260+
226261
<Row gutter={6} className="my-3">
227262
<Col span={12}>
228263
<div className="font-semibold">{t("on_update")}: </div>

src/i18n/locales/en.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ const en = {
256256
export_saved_data: "Export saved data",
257257
dbml_view: "DBML view",
258258
tab_view: "Tab view",
259+
label: "Label",
260+
many_side_label: "Many(n) side label",
259261
},
260262
};
261263

0 commit comments

Comments
 (0)