Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
142 changes: 140 additions & 2 deletions src/components/EditorCanvas/Canvas.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState, useEffect } from "react";
import { useRef, useState, useEffect, useCallback } from "react";
import {
Action,
RelationshipType,
Expand All @@ -15,6 +15,7 @@ import {
} from "../../data/constants";
import { dbToTypes } from "../../data/datatypes";
import { Toast, Modal, Input, InputNumber } from "@douyinfe/semi-ui";
import ColorPicker from "../ColorPicker";
import Table from "./Table";
import Area from "./Area";
import Relationship from "./Relationship";
Expand Down Expand Up @@ -269,6 +270,14 @@ export default function Canvas() {
field: null,
});

const [fieldForeignKeyColorModal, setFieldForeignKeyColorModal] = useState({
visible: false,
tableId: null,
fieldId: null,
field: null,
currentColor: "",
});

// Field properties modal internal state
const [fieldPropertiesPrecision, setFieldPropertiesPrecision] = useState("");
const [fieldPropertiesAccuracy, setFieldPropertiesAccuracy] = useState("");
Expand Down Expand Up @@ -1073,7 +1082,8 @@ export default function Canvas() {
if (!match) {
return {
valid: false,
message: "Invalid format. Use (x,y) where x is 0 or 1, and y is greater than 1 or *",
message:
"Invalid format. Use (x,y) where x is 0 or 1, and y is greater than 1 or *",
};
}

Expand Down Expand Up @@ -1817,6 +1827,99 @@ export default function Canvas() {
setFieldPropertiesAccuracy("");
};

const handleSetFieldForeignKeyColor = () => {
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,
);

setFieldForeignKeyColorModal({
visible: true,
tableId: fieldContextMenu.tableId,
fieldId: fieldContextMenu.fieldId,
field: field,
currentColor: field?.fkColor || settings.defaultFkColor,
});
handleFieldContextMenuClose();
}
};

const handleFieldForeignKeyColorConfirm = useCallback(
(color) => {
const { tableId, fieldId } = fieldForeignKeyColorModal;

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

updateField(tableId, fieldId, { fkColor: color });
setFieldForeignKeyColorModal({
visible: false,
tableId: null,
fieldId: null,
field: null,
currentColor: "",
});
},
[fieldForeignKeyColorModal, pushUndo, tables, t, updateField],
);

const handleFieldForeignKeyColorCancel = useCallback(() => {
setFieldForeignKeyColorModal({
visible: false,
tableId: null,
fieldId: null,
field: null,
currentColor: "",
});
}, []);

// Handle keyboard events for FK color modal
useEffect(() => {
if (!fieldForeignKeyColorModal.visible) return;

const handleKeyDown = (e) => {
if (e.key === "Enter") {
e.preventDefault();
handleFieldForeignKeyColorConfirm(
fieldForeignKeyColorModal.currentColor,
);
} else if (e.key === "Escape") {
e.preventDefault();
handleFieldForeignKeyColorCancel();
}
};

document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, [
fieldForeignKeyColorModal.visible,
fieldForeignKeyColorModal.currentColor,
handleFieldForeignKeyColorConfirm,
handleFieldForeignKeyColorCancel,
]);

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

<Modal
Expand Down Expand Up @@ -3805,6 +3909,40 @@ export default function Canvas() {
)}
</div>
</Modal>

<Modal
title={`${t("foreign_key")} Color - ${fieldForeignKeyColorModal.field?.name || "Field"}`}
visible={fieldForeignKeyColorModal.visible}
onOk={() =>
handleFieldForeignKeyColorConfirm(
fieldForeignKeyColorModal.currentColor,
)
}
onCancel={handleFieldForeignKeyColorCancel}
okText={t("confirm")}
cancelText={t("cancel")}
maskClosable={false}
keyboard={true}
>
<div style={{ padding: "20px 0" }}>
<div className="font-semibold mb-4">Select color:</div>
<ColorPicker
currentColor={fieldForeignKeyColorModal.currentColor}
onClearColor={() => {
setFieldForeignKeyColorModal((prev) => ({
...prev,
currentColor: settings.defaultFkColor,
}));
}}
onPickColor={(color) => {
setFieldForeignKeyColorModal((prev) => ({
...prev,
currentColor: color,
}));
}}
/>
</div>
</Modal>
</div>
);
}
11 changes: 11 additions & 0 deletions src/components/EditorCanvas/FieldContextMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
IconEdit2Stroked,
IconCheckboxTick,
IconMinus,
IconColorPalette,
} from "@douyinfe/semi-icons";
import { useTranslation } from "react-i18next";
import { useSettings } from "../../hooks";
Expand All @@ -25,6 +26,7 @@ export default function FieldContextMenu({
onToggleUnique,
onToggleAutoIncrement,
onEditProperties,
onSetForeignKeyColor,
}) {
const { t } = useTranslation();
const { settings } = useSettings();
Expand Down Expand Up @@ -121,6 +123,15 @@ export default function FieldContextMenu({
onClose();
},
},
// Only show FK color option for foreign key fields
...(field?.foreignK ? [{
label: `Set ${t("foreign_key")} Color`,
icon: <IconColorPalette />,
onClick: () => {
onSetForeignKeyColor();
onClose();
},
}] : []),
{
type: "divider",
},
Expand Down
4 changes: 2 additions & 2 deletions src/components/EditorCanvas/Table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ export default function Table(props) {
<p
className={`me-4 font-bold`}
style={{
color: e.foreignK ? settings.defaultFkColor : 'inherit'
color: e.foreignK ? (e.fkColor || settings.defaultFkColor) : 'inherit'
}}
>
{e.name}
Expand Down Expand Up @@ -610,7 +610,7 @@ export default function Table(props) {
fieldData.foreignK ? "font-medium" : ""
}`}
style={{
color: fieldData.foreignK ? settings.defaultFkColor : 'inherit'
color: fieldData.foreignK ? (fieldData.fkColor || settings.defaultFkColor) : 'inherit'
}}
>
{fieldData.name}
Expand Down
61 changes: 60 additions & 1 deletion src/components/EditorSidePanel/TablesTab/FieldDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import {
TagInput,
Checkbox,
Toast,
Popover,
} from "@douyinfe/semi-ui";
import { Action, ObjectType } from "../../../data/constants";
import { IconDeleteStroked } from "@douyinfe/semi-icons";
import { useDiagram, useUndoRedo } from "../../../hooks";
import { useDiagram, useUndoRedo, useSettings } from "../../../hooks";
import { useTranslation } from "react-i18next";
import { dbToTypes } from "../../../data/datatypes";
import { databases } from "../../../data/databases";
import ColorPicker from "../../ColorPicker";

export default function FieldDetails({ data, tid, index }) {
const { t } = useTranslation();
const { tables, database } = useDiagram();
const { pushUndo } = useUndoRedo();
const { updateField, deleteField } = useDiagram();
const [editField, setEditField] = useState({});
const { settings } = useSettings();

return (
<div>
Expand Down Expand Up @@ -243,6 +246,62 @@ export default function FieldDetails({ data, tid, index }) {
/>
</div>
)}
{data.foreignK && (
<div className="my-3">
<div className="font-semibold mb-2">{t("foreign_key")} Color</div>
<Popover
content={
<div className="popover-theme">
<ColorPicker
currentColor={data.fkColor || settings.defaultFkColor}
onClearColor={() => {
pushUndo({
action: Action.EDIT,
element: ObjectType.TABLE,
component: "field",
tid: tid,
fid: index,
undo: { fkColor: data.fkColor },
redo: { fkColor: undefined },
message: t("edit_table", {
tableName: tables[tid].name,
extra: "[field color]",
}),
});
updateField(tid, index, { fkColor: undefined });
}}
onPickColor={(color) => {
pushUndo({
action: Action.EDIT,
element: ObjectType.TABLE,
component: "field",
tid: tid,
fid: index,
undo: { fkColor: data.fkColor },
redo: { fkColor: color },
message: t("edit_table", {
tableName: tables[tid].name,
extra: "[field color]",
}),
});
updateField(tid, index, { fkColor: color });
}}
/>
</div>
}
trigger="click"
position="bottomLeft"
showArrow
>
<div
className="w-full h-8 rounded border-2 border-gray-300 dark:border-gray-600 cursor-pointer hover:border-blue-500 transition-colors"
style={{
backgroundColor: data.fkColor || settings.defaultFkColor,
}}
/>
</Popover>
</div>
)}
<div className="font-semibold">{t("comment")}</div>
<TextArea
className="my-2"
Expand Down
3 changes: 3 additions & 0 deletions src/components/EditorSidePanel/TablesTab/TableField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export default function TableField({ data, tid, index }) {
value={data.name}
validateStatus={data.name.trim() === "" ? "error" : "default"}
placeholder="Name"
style={{
color: data.foreignK ? (data.fkColor || settings.defaultFkColor) : 'inherit'
}}
onChange={(value) =>
updateField(tid, index, {
name: value
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ const en = {
title: "Title",
not_set: "Not set",
foreign: "Foreign",
foreign_key: "Foreign Key",
relationship_type: "Relationship type",
cardinality: "Cardinality",
on_update: "On update",
Expand Down
1 change: 1 addition & 0 deletions src/i18n/locales/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const es = {
title: "Título",
not_set: "No establecido",
foreign: "Extranjero",
foreign_key: "Clave Foránea",
relationship_type: "Tipo de relación",
cardinality: "Cardinalidad",
on_update: "Al actualizar",
Expand Down