diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx
index 28b196da4..d02916955 100644
--- a/src/components/EditorHeader/ControlPanel.jsx
+++ b/src/components/EditorHeader/ControlPanel.jsx
@@ -165,7 +165,7 @@ export default function ControlPanel({
} else if (a.element === ObjectType.RELATIONSHIP) {
deleteRelationship(a.data.relationship.id, false);
} else if (a.element === ObjectType.TYPE) {
- deleteType(types.length - 1, false);
+ deleteType(a.data.type.id, false);
} else if (a.element === ObjectType.ENUM) {
deleteEnum(enums.length - 1, false);
}
@@ -199,7 +199,7 @@ export default function ControlPanel({
} else if (a.element === ObjectType.AREA) {
addArea(a.data, false);
} else if (a.element === ObjectType.TYPE) {
- addType({ id: a.id, ...a.data }, false);
+ addType(a.data, false);
} else if (a.element === ObjectType.ENUM) {
addEnum({ id: a.id, ...a.data }, false);
}
@@ -258,9 +258,12 @@ export default function ControlPanel({
updateRelationship(a.rid, a.undo);
} else if (a.element === ObjectType.TYPE) {
if (a.component === "field_add") {
+ const type = types.find((t, i) =>
+ typeof a.tid === "number" ? i === a.tid : t.id === a.tid,
+ );
updateType(a.tid, {
- fields: types[a.tid].fields.filter(
- (_, i) => i !== types[a.tid].fields.length - 1,
+ fields: type.fields.filter((f, i) =>
+ f.id ? f.id !== a.data.field.id : i !== type.fields.length - 1,
),
});
}
@@ -334,7 +337,7 @@ export default function ControlPanel({
} else if (a.element === ObjectType.RELATIONSHIP) {
addRelationship(a.data, false);
} else if (a.element === ObjectType.TYPE) {
- addType(null, false);
+ addType(a.data, false);
} else if (a.element === ObjectType.ENUM) {
addEnum(null, false);
}
@@ -367,7 +370,7 @@ export default function ControlPanel({
} else if (a.element === ObjectType.AREA) {
deleteArea(a.data.id, false);
} else if (a.element === ObjectType.TYPE) {
- deleteType(a.id, false);
+ deleteType(a.data.type.id, false);
} else if (a.element === ObjectType.ENUM) {
deleteEnum(a.id, false);
}
@@ -436,14 +439,11 @@ export default function ControlPanel({
updateRelationship(a.rid, a.redo);
} else if (a.element === ObjectType.TYPE) {
if (a.component === "field_add") {
+ const type = types.find((t, i) =>
+ typeof a.tid === "number" ? i === a.tid : t.id === a.tid,
+ );
updateType(a.tid, {
- fields: [
- ...types[a.tid].fields,
- {
- name: "",
- type: "",
- },
- ],
+ fields: [...type.fields, a.data.field],
});
} else if (a.component === "field") {
updateType(a.tid, {
diff --git a/src/components/EditorSidePanel/TypesTab/TypeInfo.jsx b/src/components/EditorSidePanel/TypesTab/TypeInfo.jsx
index f3c7337a5..cfbe75c29 100644
--- a/src/components/EditorSidePanel/TypesTab/TypeInfo.jsx
+++ b/src/components/EditorSidePanel/TypesTab/TypeInfo.jsx
@@ -13,6 +13,7 @@ import { IconDeleteStroked, IconPlus } from "@douyinfe/semi-icons";
import { useUndoRedo, useTypes, useDiagram, useLayout } from "../../../hooks";
import TypeField from "./TypeField";
import { useTranslation } from "react-i18next";
+import { nanoid } from "nanoid";
export default function TypeInfo({ index, data }) {
const { layout } = useLayout();
@@ -22,8 +23,11 @@ export default function TypeInfo({ index, data }) {
const [editField, setEditField] = useState({});
const { t } = useTranslation();
+ // TODO: remove indexes, not a valid case after adding id to types
+ const typeId = data.id ?? index;
+
return (
-
+
@@ -41,7 +45,7 @@ export default function TypeInfo({ index, data }) {
placeholder={t("name")}
className="ms-2"
onChange={(value) => {
- updateType(index, { name: value });
+ updateType(typeId, { name: value });
tables.forEach((table) => {
table.fields.forEach((field) => {
if (field.type.toLowerCase() === data.name.toLowerCase()) {
@@ -71,7 +75,7 @@ export default function TypeInfo({ index, data }) {
action: Action.EDIT,
element: ObjectType.TYPE,
component: "self",
- tid: index,
+ tid: typeId,
undo: editField,
redo: { name: e.target.value },
updatedFields,
@@ -103,7 +107,7 @@ export default function TypeInfo({ index, data }) {
placeholder={t("comment")}
rows={1}
onChange={(value) =>
- updateType(index, { comment: value }, false)
+ updateType(typeId, { comment: value }, false)
}
onFocus={(e) => setEditField({ comment: e.target.value })}
onBlur={(e) => {
@@ -114,7 +118,7 @@ export default function TypeInfo({ index, data }) {
action: Action.EDIT,
element: ObjectType.TYPE,
component: "self",
- tid: index,
+ tid: typeId,
undo: editField,
redo: { comment: e.target.value },
message: t("edit_type", {
@@ -135,13 +139,22 @@ export default function TypeInfo({ index, data }) {
icon={}
disabled={layout.readOnly}
onClick={() => {
+ const newField = {
+ name: "",
+ type: "",
+ id: nanoid(),
+ };
setUndoStack((prev) => [
...prev,
{
action: Action.EDIT,
element: ObjectType.TYPE,
component: "field_add",
- tid: index,
+ data: {
+ field: newField,
+ index: data.fields.length,
+ },
+ tid: typeId,
message: t("edit_type", {
typeName: data.name,
extra: "[add field]",
@@ -149,14 +162,8 @@ export default function TypeInfo({ index, data }) {
},
]);
setRedoStack([]);
- updateType(index, {
- fields: [
- ...data.fields,
- {
- name: "",
- type: "",
- },
- ],
+ updateType(typeId, {
+ fields: [...data.fields, newField],
});
}}
block
@@ -170,7 +177,7 @@ export default function TypeInfo({ index, data }) {
type="danger"
disabled={layout.readOnly}
icon={}
- onClick={() => deleteType(index)}
+ onClick={() => deleteType(typeId)}
>
{t("delete")}
diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx
index 88f291beb..efe8bc9bd 100644
--- a/src/components/Workspace.jsx
+++ b/src/components/Workspace.jsx
@@ -26,6 +26,7 @@ import { databases } from "../data/databases";
import { isRtl } from "../i18n/utils/rtl";
import { useSearchParams } from "react-router-dom";
import { get, SHARE_FILENAME } from "../api/gists";
+import { nanoid } from "nanoid";
export const IdContext = createContext({
gistId: "",
@@ -196,7 +197,23 @@ export default function WorkSpace() {
setTasks(d.todos ?? []);
setTransform({ pan: d.pan, zoom: d.zoom });
if (databases[database].hasTypes) {
- setTypes(d.types ?? []);
+ if (d.types) {
+ setTypes(
+ d.types.map((t) =>
+ t.id
+ ? t
+ : {
+ ...t,
+ id: nanoid(),
+ fields: t.fields.map((f) =>
+ f.id ? f : { ...f, id: nanoid() },
+ ),
+ },
+ ),
+ );
+ } else {
+ setTypes([]);
+ }
}
if (databases[database].hasEnums) {
setEnums(d.enums ?? []);
@@ -238,7 +255,23 @@ export default function WorkSpace() {
setUndoStack([]);
setRedoStack([]);
if (databases[database].hasTypes) {
- setTypes(diagram.types ?? []);
+ if (diagram.types) {
+ setTypes(
+ diagram.types.map((t) =>
+ t.id
+ ? t
+ : {
+ ...t,
+ id: nanoid(),
+ fields: t.fields.map((f) =>
+ f.id ? f : { ...f, id: nanoid() },
+ ),
+ },
+ ),
+ );
+ } else {
+ setTypes([]);
+ }
}
if (databases[database].hasEnums) {
setEnums(diagram.enums ?? []);
@@ -277,7 +310,23 @@ export default function WorkSpace() {
setUndoStack([]);
setRedoStack([]);
if (databases[database].hasTypes) {
- setTypes(diagram.types ?? []);
+ if (diagram.types) {
+ setTypes(
+ diagram.types.map((t) =>
+ t.id
+ ? t
+ : {
+ ...t,
+ id: nanoid(),
+ fields: t.fields.map((f) =>
+ f.id ? f : { ...f, id: nanoid() },
+ ),
+ },
+ ),
+ );
+ } else {
+ setTypes([]);
+ }
}
if (databases[database].hasEnums) {
setEnums(diagram.enums ?? []);
@@ -308,7 +357,23 @@ export default function WorkSpace() {
setAreas(parsedDiagram.subjectAreas);
setTransform(parsedDiagram.transform);
if (databases[parsedDiagram.database].hasTypes) {
- setTypes(parsedDiagram.types ?? []);
+ if (parsedDiagram.types) {
+ setTypes(
+ parsedDiagram.types.map((t) =>
+ t.id
+ ? t
+ : {
+ ...t,
+ id: nanoid(),
+ fields: t.fields.map((f) =>
+ f.id ? f : { ...f, id: nanoid() },
+ ),
+ },
+ ),
+ );
+ } else {
+ setTypes([]);
+ }
}
if (databases[parsedDiagram.database].hasEnums) {
setEnums(parsedDiagram.enums ?? []);
diff --git a/src/context/TypesContext.jsx b/src/context/TypesContext.jsx
index 24f78436e..4eb4ce8d5 100644
--- a/src/context/TypesContext.jsx
+++ b/src/context/TypesContext.jsx
@@ -3,6 +3,7 @@ import { Action, ObjectType } from "../data/constants";
import { useUndoRedo } from "../hooks";
import { Toast } from "@douyinfe/semi-ui";
import { useTranslation } from "react-i18next";
+import { nanoid } from "nanoid";
export const TypesContext = createContext(null);
@@ -12,16 +13,18 @@ export default function TypesContextProvider({ children }) {
const { setUndoStack, setRedoStack } = useUndoRedo();
const addType = (data, addToHistory = true) => {
+ const id = nanoid();
if (data) {
setTypes((prev) => {
const temp = prev.slice();
- temp.splice(data.id, 0, data);
+ temp.splice(data.index, 0, data.type);
return temp;
});
} else {
setTypes((prev) => [
...prev,
{
+ id,
name: `type_${prev.length}`,
fields: [],
comment: "",
@@ -32,6 +35,15 @@ export default function TypesContextProvider({ children }) {
setUndoStack((prev) => [
...prev,
{
+ data: {
+ index: types.length,
+ type: data?.type ?? {
+ id,
+ name: `type_${prev.length}`,
+ fields: [],
+ comment: "",
+ },
+ },
action: Action.ADD,
element: ObjectType.TYPE,
message: t("add_type"),
@@ -43,27 +55,35 @@ export default function TypesContextProvider({ children }) {
const deleteType = (id, addToHistory = true) => {
if (addToHistory) {
+ const deletedTypeIndex = types.findIndex((e, i) =>
+ typeof id === "number" ? i === id : e.id === id,
+ );
Toast.success(t("type_deleted"));
setUndoStack((prev) => [
...prev,
{
action: Action.DELETE,
element: ObjectType.TYPE,
- id: id,
- data: types[id],
+ data: { type: types[deletedTypeIndex], index: deletedTypeIndex },
message: t("delete_type", {
- typeName: types[id].name,
+ typeName: types[deletedTypeIndex].name,
}),
},
]);
setRedoStack([]);
}
- setTypes((prev) => prev.filter((e, i) => i !== id));
+ setTypes((prev) =>
+ prev.filter((e, i) => (typeof id === "number" ? i !== id : e.id !== id)),
+ );
};
const updateType = (id, values) => {
setTypes((prev) =>
- prev.map((e, i) => (i === id ? { ...e, ...values } : e)),
+ prev.map((item, index) => {
+ const isMatch = typeof id === "number" ? index === id : item.id === id;
+
+ return isMatch ? { ...item, ...values } : item;
+ }),
);
};
diff --git a/src/data/schemas.js b/src/data/schemas.js
index 4955821da..79476fa3b 100644
--- a/src/data/schemas.js
+++ b/src/data/schemas.js
@@ -97,12 +97,14 @@ export const noteSchema = {
export const typeSchema = {
type: "object",
properties: {
+ id: { type: ["string"] },
name: { type: "string" },
fields: {
type: "array",
items: {
type: "object",
properties: {
+ id: { type: ["string"] },
name: { type: "string" },
type: { type: "string" },
values: {