drawDB/src/pages/editor.jsx

428 lines
11 KiB
React
Raw Normal View History

2023-09-19 20:48:51 +08:00
import React, { useState, createContext, useEffect } from "react";
2023-09-19 20:46:48 +08:00
import Sidebar from "../components/sidebar";
import ControlPanel from "../components/control_panel";
2023-09-19 20:47:01 +08:00
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
2023-09-19 20:47:43 +08:00
import Canvas from "../components/canvas";
2023-09-19 20:47:01 +08:00
import EditorPanel from "../components/editor_panel";
2023-09-19 20:49:57 +08:00
import {
Tab,
defaultTableTheme,
defaultNoteTheme,
Action,
ObjectType,
} from "../data/data";
2023-09-19 20:48:46 +08:00
export const LayoutContext = createContext();
2023-09-19 20:48:48 +08:00
export const TableContext = createContext();
2023-09-19 20:48:49 +08:00
export const AreaContext = createContext();
2023-09-19 20:48:57 +08:00
export const TabContext = createContext();
2023-09-19 20:49:09 +08:00
export const NoteContext = createContext();
2023-09-19 20:49:14 +08:00
export const SettingsContext = createContext();
2023-09-19 20:49:41 +08:00
export const UndoRedoContext = createContext();
2023-09-19 20:50:28 +08:00
export const SelectContext = createContext();
2023-09-19 20:48:46 +08:00
2023-09-19 20:46:46 +08:00
export default function Editor(props) {
2023-09-19 20:46:56 +08:00
const [code, setCode] = useState("");
const [tables, setTables] = useState([]);
const [relationships, setRelationships] = useState([]);
2023-09-19 20:48:04 +08:00
const [areas, setAreas] = useState([]);
2023-09-19 20:49:09 +08:00
const [notes, setNotes] = useState([]);
2023-09-19 20:48:30 +08:00
const [resize, setResize] = useState(false);
2023-09-19 20:49:39 +08:00
const [width, setWidth] = useState(340);
2023-09-19 20:48:57 +08:00
const [tab, setTab] = useState(Tab.tables);
2023-09-19 20:48:34 +08:00
const [layout, setLayout] = useState({
header: true,
sidebar: true,
services: true,
tables: true,
2023-09-19 20:48:55 +08:00
areas: true,
2023-09-19 20:48:34 +08:00
relationships: true,
issues: true,
editor: true,
2023-09-19 20:49:09 +08:00
notes: true,
2023-09-19 20:48:35 +08:00
fullscreen: false,
2023-09-19 20:48:34 +08:00
});
2023-09-19 20:49:14 +08:00
const [settings, setSettings] = useState({
strictMode: false,
2023-09-19 20:49:16 +08:00
showFieldSummary: true,
2023-09-19 20:49:36 +08:00
zoom: 1,
2023-09-19 20:49:57 +08:00
pan: { x: 0, y: 0 },
2023-09-19 20:49:37 +08:00
showGrid: true,
2023-09-19 20:49:14 +08:00
});
2023-09-19 20:49:41 +08:00
const [undoStack, setUndoStack] = useState([]);
const [redoStack, setRedoStack] = useState([]);
2023-09-19 20:50:28 +08:00
const [selectedElement, setSelectedElement] = useState({
element: ObjectType.NONE,
id: -1,
openDialogue: false,
openCollapse: false,
});
2023-09-19 20:48:31 +08:00
const dragHandler = (e) => {
if (!resize) return;
const w = e.clientX;
2023-09-19 20:49:39 +08:00
if (w > 340) setWidth(w);
2023-09-19 20:48:31 +08:00
};
2023-09-19 20:46:56 +08:00
2023-09-19 20:49:57 +08:00
const addTable = (addToHistory = true, data) => {
if (data) {
setTables((prev) => {
const temp = prev.slice();
temp.splice(data.id, 0, data);
return temp.map((t, i) => ({ ...t, id: i }));
});
} else {
setTables((prev) => [
...prev,
{
id: prev.length,
name: `table_${prev.length}`,
x: -settings.pan.x,
y: -settings.pan.y,
fields: [
{
name: "id",
type: "UUID",
default: "",
check: "",
primary: true,
unique: true,
notNull: true,
increment: true,
comment: "",
2023-09-19 20:50:04 +08:00
id: 0,
2023-09-19 20:49:57 +08:00
},
],
comment: "",
indices: [],
color: defaultTableTheme,
},
]);
}
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.ADD,
element: ObjectType.TABLE,
},
]);
setRedoStack([]);
}
};
2023-09-19 20:50:04 +08:00
const updateField = (tid, fid, updatedValues) => {
setTables((prev) =>
prev.map((table, i) => {
if (tid === i) {
return {
...table,
fields: table.fields.map((field, j) =>
fid === j ? { ...field, ...updatedValues } : field
),
};
}
return table;
})
);
};
2023-09-19 20:49:57 +08:00
const addArea = (addToHistory = true, data) => {
if (data) {
setAreas((prev) => {
const temp = prev.slice();
temp.splice(data.id, 0, data);
return temp.map((t, i) => ({ ...t, id: i }));
});
} else {
setAreas((prev) => [
...prev,
{
id: prev.length,
name: `area_${prev.length}`,
x: -settings.pan.x,
y: -settings.pan.y,
width: 200,
height: 200,
color: defaultTableTheme,
},
]);
}
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.ADD,
element: ObjectType.AREA,
},
]);
setRedoStack([]);
}
};
const addNote = (addToHistory = true, data) => {
if (data) {
setNotes((prev) => {
const temp = prev.slice();
temp.splice(data.id, 0, data);
return temp.map((t, i) => ({ ...t, id: i }));
});
} else {
setNotes((prev) => [
...prev,
{
id: prev.length,
x: -settings.pan.x,
y: -settings.pan.y,
title: `note_${prev.length}`,
content: "",
color: defaultNoteTheme,
height: 88,
},
]);
}
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.ADD,
element: ObjectType.NOTE,
},
]);
setRedoStack([]);
}
};
const addRelationship = (addToHistory = true, data) => {
if (addToHistory) {
setRelationships((prev) => {
setUndoStack((prevUndo) => [
...prevUndo,
{
action: Action.ADD,
element: ObjectType.RELATIONSHIP,
data: data,
},
]);
setRedoStack([]);
return [...prev, data];
});
} else {
setRelationships((prev) => {
const temp = prev.slice();
temp.splice(data.id, 0, data);
return temp.map((t, i) => ({ ...t, id: i }));
});
}
};
const deleteTable = (id, addToHistory = true) => {
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.DELETE,
element: ObjectType.TABLE,
data: tables[id],
},
]);
setRedoStack([]);
}
setTables((prev) =>
prev.filter((e) => e.id !== id).map((e, i) => ({ ...e, id: i }))
);
2023-09-19 20:50:28 +08:00
if (id === selectedElement.id) {
setSelectedElement({
element: ObjectType.NONE,
id: -1,
openDialogue: false,
openCollapse: false,
});
}
2023-09-19 20:49:57 +08:00
};
const deleteArea = (id, addToHistory = true) => {
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.DELETE,
element: ObjectType.AREA,
data: areas[id],
},
]);
setRedoStack([]);
}
setAreas((prev) =>
prev.filter((e) => e.id !== id).map((e, i) => ({ ...e, id: i }))
);
};
const deleteNote = (id, addToHistory = true) => {
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.DELETE,
element: ObjectType.NOTE,
data: notes[id],
},
]);
setRedoStack([]);
}
setNotes((prev) =>
prev.filter((e) => e.id !== id).map((e, i) => ({ ...e, id: i }))
);
};
const deleteRelationship = (id, addToHistory = true) => {
if (addToHistory) {
setUndoStack((prev) => [
...prev,
{
action: Action.DELETE,
element: ObjectType.RELATIONSHIP,
data: relationships[id],
},
]);
setRedoStack([]);
}
setRelationships((prev) =>
prev.filter((e) => e.id !== id).map((e, i) => ({ ...e, id: i }))
);
};
2023-09-19 20:50:15 +08:00
const updateArea = (id, values) => {
setAreas((prev) =>
prev.map((t) => {
if (t.id === id) {
return {
...t,
...values,
};
}
return t;
})
);
};
const updateNote = (id, values, addToHistory = true) => {
2023-09-19 20:50:00 +08:00
setNotes((prev) =>
prev.map((t) => {
if (t.id === id) {
return {
...t,
...values,
};
}
return t;
})
);
2023-09-19 20:50:04 +08:00
};
2023-09-19 20:50:00 +08:00
2023-09-19 20:50:15 +08:00
const updateTable = (id, updatedValues, updateRelationships = false) => {
setTables((prev) =>
prev.map((table) => {
if (table.id === id) {
if (updateRelationships) {
setRelationships((prev) =>
prev.map((r) => {
if (r.startTableId === id) {
return {
...r,
startX: updatedValues.x + 15,
startY: updatedValues.y + r.startFieldId * 36 + 69,
};
} else if (r.endTableId === id) {
return {
...r,
endX: updatedValues.x + 15,
endY: updatedValues.y + r.endFieldId * 36 + 69,
};
}
return r;
})
);
}
return {
...table,
...updatedValues,
};
}
return table;
})
);
};
2023-09-19 20:48:57 +08:00
useEffect(() => {
2023-09-19 20:49:57 +08:00
document.title = "Editor - drawDB";
2023-09-19 20:48:57 +08:00
}, []);
2023-09-19 20:48:51 +08:00
2023-09-19 20:46:46 +08:00
return (
2023-09-19 20:48:49 +08:00
<LayoutContext.Provider value={{ layout, setLayout }}>
<TableContext.Provider
2023-09-19 20:49:57 +08:00
value={{
tables,
setTables,
addTable,
2023-09-19 20:50:15 +08:00
updateTable,
2023-09-19 20:50:04 +08:00
updateField,
2023-09-19 20:49:57 +08:00
deleteTable,
relationships,
setRelationships,
addRelationship,
deleteRelationship,
}}
2023-09-19 20:48:49 +08:00
>
2023-09-19 20:49:57 +08:00
<AreaContext.Provider
2023-09-19 20:50:15 +08:00
value={{ areas, setAreas, updateArea, addArea, deleteArea }}
2023-09-19 20:49:57 +08:00
>
<NoteContext.Provider
2023-09-19 20:50:15 +08:00
value={{ notes, setNotes, updateNote, addNote, deleteNote }}
2023-09-19 20:49:57 +08:00
>
2023-09-19 20:49:09 +08:00
<TabContext.Provider value={{ tab, setTab }}>
2023-09-19 20:49:39 +08:00
<SettingsContext.Provider value={{ settings, setSettings }}>
2023-09-19 20:49:41 +08:00
<UndoRedoContext.Provider
value={{ undoStack, redoStack, setUndoStack, setRedoStack }}
>
2023-09-19 20:50:28 +08:00
<SelectContext.Provider
value={{ selectedElement, setSelectedElement }}
>
<div className="h-[100vh] overflow-hidden">
<ControlPanel />
<div
className={
layout.header
? `flex h-[calc(100vh-123.93px)]`
: `flex h-[calc(100vh-51.97px)]`
}
onMouseUp={() => setResize(false)}
onMouseMove={dragHandler}
>
<DndProvider backend={HTML5Backend}>
{layout.sidebar && (
<EditorPanel
code={code}
setCode={setCode}
resize={resize}
setResize={setResize}
width={width}
/>
)}
<Canvas code={code} setCode={setCode} />
</DndProvider>
{layout.services && <Sidebar />}
</div>
2023-09-19 20:49:41 +08:00
</div>
2023-09-19 20:50:28 +08:00
</SelectContext.Provider>
2023-09-19 20:49:41 +08:00
</UndoRedoContext.Provider>
2023-09-19 20:49:14 +08:00
</SettingsContext.Provider>
2023-09-19 20:49:09 +08:00
</TabContext.Provider>
</NoteContext.Provider>
2023-09-19 20:48:49 +08:00
</AreaContext.Provider>
2023-09-19 20:48:48 +08:00
</TableContext.Provider>
2023-09-19 20:48:46 +08:00
</LayoutContext.Provider>
2023-09-19 20:46:46 +08:00
);
}