Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e57dcb4
Changed layout of TableInfo to improve UX
dvd-22 Sep 29, 2025
b3d4808
feat: split precision fields and move size/precision from popover to …
lethalSopaper Oct 8, 2025
4a6dc6d
fix: remove unused event parameters in precision input handlers
lethalSopaper Oct 8, 2025
83c724c
feat: enforce accuracy < precision constraint for numeric field valid…
lethalSopaper Oct 8, 2025
ff4e02e
feat: Field context menu now support field properties.
lethalSopaper Oct 8, 2025
89c1307
Merge remote-tracking branch 'lidsol/main' into feat-precision-accura…
lethalSopaper Oct 8, 2025
9d36171
feat: Add customizable default foreign key color setting
lethalSopaper Oct 9, 2025
31baa8a
fix: linter passing without errors
lethalSopaper Oct 9, 2025
ab5b43b
Merge pull request #64 from lethalSopaper/feat-precision-accuracy-sec…
HansMarcus01 Oct 9, 2025
860a6d0
fix default data length setting when editing a field type
javierariashe Oct 12, 2025
4d86ce8
removed automatic uppercase and lowercase use based on default settings
javierariashe Oct 15, 2025
70144b3
fix typo in TableInfo which caused a warning
javierariashe Oct 15, 2025
3afc0e2
Added cardinality to subtypes
dvd-22 Oct 18, 2025
a36e7fe
Merge branch 'LIDSOL:main' into feat-cardinality-to-subtypes
dvd-22 Oct 18, 2025
9396574
Merge pull request #70 from dvd-22/feat-cardinality-to-subtypes
HansMarcus01 Oct 22, 2025
6d78fb4
Removing cardinality start from subtypes relations
HansMarcus01 Oct 22, 2025
1dc79b4
Merge pull request #71 from LIDSOL/fix-removing-cardinalityStart-subtype
HansMarcus01 Oct 22, 2025
9f4c22e
Merge pull request #67 from javierariashe/bug/default-data-length
HansMarcus01 Oct 22, 2025
68797c2
Merge pull request #68 from javierariashe/fix-caps-default
HansMarcus01 Oct 22, 2025
ee4b707
Merge pull request #69 from javierariashe/bug/fix-icon-position-warning
HansMarcus01 Oct 22, 2025
0e35a6f
Merge branch 'feat-fk-relationship-color' into main_copy
lethalSopaper Oct 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 248 additions & 1 deletion src/components/EditorCanvas/Canvas.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
Notation,
Tab,
} from "../../data/constants";
import { Toast, Modal, Input } from "@douyinfe/semi-ui";
import { dbToTypes } from "../../data/datatypes";
import { Toast, Modal, Input, InputNumber } from "@douyinfe/semi-ui";
import Table from "./Table";
import Area from "./Area";
import Relationship from "./Relationship";
Expand Down Expand Up @@ -82,7 +83,9 @@ export default function Canvas() {

const {
tables,
database,
updateTable,
updateField,
relationships,
addRelationship,
addTable,
Expand Down Expand Up @@ -259,7 +262,19 @@ export default function Canvas() {
relatedField: null, // { tableId, fieldId, tableName, fieldName }
});

const [fieldPropertiesModal, setFieldPropertiesModal] = useState({
visible: false,
tableId: null,
fieldId: null,
field: null,
});

// Field properties modal internal state
const [fieldPropertiesPrecision, setFieldPropertiesPrecision] = useState("");
const [fieldPropertiesAccuracy, setFieldPropertiesAccuracy] = useState("");

const fieldRenameInputRef = useRef(null);
const fieldPropertiesInputRef = useRef(null);
const tableRenameInputRef = useRef(null);
const relationshipRenameInputRef = useRef(null);
const changeCardinalityInputRef = useRef(null);
Expand Down Expand Up @@ -303,6 +318,34 @@ export default function Canvas() {
}
}, [relationshipRenameModal.visible]);

// Initialize field properties modal values when it opens
useEffect(() => {
if (fieldPropertiesModal.visible && fieldPropertiesModal.field) {
const field = fieldPropertiesModal.field;
if (field.size && field.size.includes(",")) {
const [prec, acc] = field.size.split(",");
setFieldPropertiesPrecision(parseInt(prec) || "");
setFieldPropertiesAccuracy(parseInt(acc?.trim()) || "");
} else {
setFieldPropertiesPrecision("");
setFieldPropertiesAccuracy("");
}
}
}, [fieldPropertiesModal.visible, fieldPropertiesModal.field]);

// Auto-focus field properties input when modal opens
useEffect(() => {
if (fieldPropertiesModal.visible && fieldPropertiesInputRef.current) {
const timer = setTimeout(() => {
if (fieldPropertiesInputRef.current) {
fieldPropertiesInputRef.current.focus();
fieldPropertiesInputRef.current.select();
}
}, 100);
return () => clearTimeout(timer);
}
}, [fieldPropertiesModal.visible]);

// Auto select when the change cardinality modal opens
useEffect(() => {
if (changeCardinalityModal.visible && changeCardinalityInputRef.current) {
Expand Down Expand Up @@ -1701,6 +1744,79 @@ export default function Canvas() {
});
};

const handleFieldEditProperties = () => {
if (
fieldContextMenu.tableId !== null &&
fieldContextMenu.fieldId !== null
) {
const table = tables.find((t) => t.id === fieldContextMenu.tableId);
const field = table?.fields.find(
(f) => f.id === fieldContextMenu.fieldId,
);

setFieldPropertiesModal({
visible: true,
tableId: fieldContextMenu.tableId,
fieldId: fieldContextMenu.fieldId,
field: field,
});
handleFieldContextMenuClose();
}
};

const handleFieldPropertiesConfirm = () => {
const { tableId, fieldId } = fieldPropertiesModal;

let newSize = "";
if (fieldPropertiesPrecision && fieldPropertiesAccuracy !== "") {
newSize = `${fieldPropertiesPrecision},${fieldPropertiesAccuracy}`;
} else if (fieldPropertiesPrecision) {
newSize = fieldPropertiesPrecision.toString();
}

const updates = { size: newSize };

pushUndo({
action: Action.EDIT,
element: ObjectType.TABLE,
component: "field",
tid: tableId,
fid: fieldId,
undo: {
size:
tables
.find((t) => t.id === tableId)
?.fields.find((f) => f.id === fieldId)?.size || "",
},
redo: updates,
message: t("edit_table", {
tableName: tables.find((t) => t.id === tableId)?.name || "",
extra: "[field properties]",
}),
});

updateField(tableId, fieldId, updates);
setFieldPropertiesModal({
visible: false,
tableId: null,
fieldId: null,
field: null,
});
setFieldPropertiesPrecision("");
setFieldPropertiesAccuracy("");
};

const handleFieldPropertiesCancel = () => {
setFieldPropertiesModal({
visible: false,
tableId: null,
fieldId: null,
field: null,
});
setFieldPropertiesPrecision("");
setFieldPropertiesAccuracy("");
};

const handleEditNoteContent = () => {
if (noteContextMenu.noteId !== null) {
// Focus on the textarea for the note
Expand Down Expand Up @@ -3294,6 +3410,7 @@ export default function Canvas() {
onToggleNotNull={handleToggleFieldNotNull}
onToggleUnique={handleToggleFieldUnique}
onToggleAutoIncrement={handleToggleFieldAutoIncrement}
onEditProperties={handleFieldEditProperties}
/>

<Modal
Expand Down Expand Up @@ -3558,6 +3675,136 @@ export default function Canvas() {
</p>
</div>
</Modal>

<Modal
title={`Edit Properties - ${fieldPropertiesModal.field?.name || "Field"}`}
visible={
fieldPropertiesModal.visible &&
fieldPropertiesModal.field &&
dbToTypes[database] &&
dbToTypes[database][fieldPropertiesModal.field.type] &&
(dbToTypes[database][fieldPropertiesModal.field.type].hasPrecision ||
dbToTypes[database][fieldPropertiesModal.field.type].isSized)
}
onOk={handleFieldPropertiesConfirm}
onCancel={handleFieldPropertiesCancel}
okText={t("confirm")}
cancelText={t("cancel")}
maskClosable={false}
keyboard={false}
>
<div style={{ padding: "20px 0" }}>
{fieldPropertiesModal.field &&
dbToTypes[database] &&
dbToTypes[database][fieldPropertiesModal.field.type] &&
dbToTypes[database][fieldPropertiesModal.field.type].hasPrecision ? (
<>
<div style={{ marginBottom: "16px" }}>
<label
style={{
display: "block",
marginBottom: "8px",
fontWeight: "bold",
}}
>
Total Digits (Precision):
</label>
<InputNumber
ref={fieldPropertiesInputRef}
value={fieldPropertiesPrecision}
onChange={(value) => {
setFieldPropertiesPrecision(value);
// Auto-adjust accuracy if it would exceed the new limit
if (
fieldPropertiesAccuracy !== "" &&
value &&
fieldPropertiesAccuracy >= value
) {
setFieldPropertiesAccuracy(Math.max(0, value - 1));
}
}}
placeholder="Enter total digits"
min={1}
max={65}
className="w-full"
onKeyPress={(e) => {
if (e.key === "Enter") {
handleFieldPropertiesConfirm();
}
}}
/>
</div>
<div style={{ marginBottom: "16px" }}>
<label
style={{
display: "block",
marginBottom: "8px",
fontWeight: "bold",
}}
>
Decimal Digits (Accuracy):
</label>
<InputNumber
value={fieldPropertiesAccuracy}
onChange={(value) => {
// Ensure accuracy doesn't exceed precision - 1
const maxAccuracy = fieldPropertiesPrecision
? Math.max(0, fieldPropertiesPrecision - 1)
: 9;
const clampedValue = fieldPropertiesPrecision
? Math.min(value || 0, maxAccuracy)
: value;
setFieldPropertiesAccuracy(clampedValue);
}}
placeholder="Enter decimal digits"
min={0}
max={
fieldPropertiesPrecision
? Math.max(0, fieldPropertiesPrecision - 1)
: 9
}
className="w-full"
onKeyPress={(e) => {
if (e.key === "Enter") {
handleFieldPropertiesConfirm();
}
}}
/>
</div>
<div
style={{ fontSize: "12px", color: "#666", marginTop: "8px" }}
>
Example: Precision=10, Accuracy=2 allows values like 12345678.90
</div>
</>
) : (
<div style={{ marginBottom: "16px" }}>
<label
style={{
display: "block",
marginBottom: "8px",
fontWeight: "bold",
}}
>
Size:
</label>
<InputNumber
ref={fieldPropertiesInputRef}
value={fieldPropertiesPrecision}
onChange={setFieldPropertiesPrecision}
placeholder="Enter size"
min={1}
className="w-full"
onKeyPress={(e) => {
if (e.key === "Enter") {
handleFieldPropertiesConfirm();
}
}}
/>
</div>
)}
</div>
</Modal>
</div>
);
}
9 changes: 9 additions & 0 deletions src/components/EditorCanvas/FieldContextMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function FieldContextMenu({
onToggleNotNull,
onToggleUnique,
onToggleAutoIncrement,
onEditProperties,
}) {
const { t } = useTranslation();
const { settings } = useSettings();
Expand Down Expand Up @@ -78,6 +79,14 @@ export default function FieldContextMenu({
onClose();
},
},
{
label: "Edit Properties",
icon: <IconEdit />,
onClick: () => {
onEditProperties();
onClose();
},
},
{
label: field?.primary ? "Remove Primary Key" : "Set as Primary Key",
icon: <IconKeyStroked />,
Expand Down
Loading