Abstract save state from editor
This commit is contained in:
parent
d347e856a8
commit
1132edbbb3
@ -1,4 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Button, Popover, Input, Toast } from "@douyinfe/semi-ui";
|
||||
import {
|
||||
IconEdit,
|
||||
@ -13,19 +13,19 @@ import {
|
||||
defaultTableTheme,
|
||||
State,
|
||||
} from "../data/data";
|
||||
import { StateContext } from "../pages/Editor";
|
||||
import useLayout from "../hooks/useLayout";
|
||||
import useSettings from "../hooks/useSettings";
|
||||
import useUndoRedo from "../hooks/useUndoRedo";
|
||||
import useSelect from "../hooks/useSelect";
|
||||
import useAreas from "../hooks/useAreas";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function Area(props) {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const [editField, setEditField] = useState({});
|
||||
const { setState } = useContext(StateContext);
|
||||
const { layout } = useLayout();
|
||||
const { settings } = useSettings();
|
||||
const { setSaveState } = useSaveState();
|
||||
const { updateArea, deleteArea } = useAreas();
|
||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||
const { selectedElement, setSelectedElement } = useSelect();
|
||||
@ -100,7 +100,7 @@ export default function Area(props) {
|
||||
...prev,
|
||||
open: false,
|
||||
}));
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
stopPropagation
|
||||
content={
|
||||
@ -145,7 +145,7 @@ export default function Area(props) {
|
||||
updateArea(props.areaData.id, {
|
||||
color: defaultTableTheme,
|
||||
});
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Empty,
|
||||
Row,
|
||||
@ -26,12 +26,12 @@ import {
|
||||
ObjectType,
|
||||
State,
|
||||
} from "../data/data";
|
||||
import { StateContext } from "../pages/Editor";
|
||||
import useUndoRedo from "../hooks/useUndoRedo";
|
||||
import useAreas from "../hooks/useAreas";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function AreaOverview() {
|
||||
const { setState } = useContext(StateContext);
|
||||
const { setSaveState } = useSaveState();
|
||||
const { areas, addArea, deleteArea, updateArea } = useAreas();
|
||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||
const [editField, setEditField] = useState({});
|
||||
@ -141,7 +141,7 @@ export default function AreaOverview() {
|
||||
size="small"
|
||||
onClick={() => {
|
||||
updateArea(i, { color: defaultTableTheme });
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
IconCaretdown,
|
||||
IconChevronRight,
|
||||
@ -43,7 +43,6 @@ import {
|
||||
jsonToMariaDB,
|
||||
jsonToSQLServer,
|
||||
} from "../utils/toSQL";
|
||||
import { StateContext } from "../pages/Editor";
|
||||
import { IconAddTable, IconAddArea, IconAddNote } from "./CustomIcons";
|
||||
import { ObjectType, Action, Tab, State, Cardinality } from "../data/data";
|
||||
import jsPDF from "jspdf";
|
||||
@ -68,6 +67,7 @@ import { dataURItoBlob } from "../utils/utils";
|
||||
import useAreas from "../hooks/useAreas";
|
||||
import useNotes from "../hooks/useNotes";
|
||||
import useTypes from "../hooks/useTypes";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function ControlPanel({
|
||||
diagramId,
|
||||
@ -117,7 +117,7 @@ export default function ControlPanel({
|
||||
message: "",
|
||||
});
|
||||
const [data, setData] = useState(null);
|
||||
const { state, setState } = useContext(StateContext);
|
||||
const { saveState, setSaveState } = useSaveState();
|
||||
const { layout, setLayout } = useLayout();
|
||||
const { settings, setSettings } = useSettings();
|
||||
const {
|
||||
@ -734,7 +734,7 @@ export default function ControlPanel({
|
||||
copy();
|
||||
del();
|
||||
};
|
||||
const save = () => setState(State.SAVING);
|
||||
const save = () => setSaveState(State.SAVING);
|
||||
const open = () => setVisible(MODAL.OPEN);
|
||||
const saveDiagramAs = () => setVisible(MODAL.SAVEAS);
|
||||
const loadDiagram = async (id) => {
|
||||
@ -1036,7 +1036,7 @@ export default function ControlPanel({
|
||||
Exit: {
|
||||
function: () => {
|
||||
save();
|
||||
if (state === State.SAVED) navigate("/");
|
||||
if (saveState === State.SAVED) navigate("/");
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -2256,7 +2256,7 @@ export default function ControlPanel({
|
||||
}
|
||||
|
||||
function getState() {
|
||||
switch (state) {
|
||||
switch (saveState) {
|
||||
case State.NONE:
|
||||
return "No changes";
|
||||
case State.LOADING:
|
||||
@ -2378,7 +2378,7 @@ export default function ControlPanel({
|
||||
size="small"
|
||||
type="tertiary"
|
||||
icon={
|
||||
state === State.LOADING || state === State.SAVING ? (
|
||||
saveState === State.LOADING || saveState === State.SAVING ? (
|
||||
<Spin size="small" />
|
||||
) : null
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { StateContext } from "../pages/Editor";
|
||||
import { useState } from "react";
|
||||
import { Action, ObjectType, noteThemes, Tab, State } from "../data/data";
|
||||
import { Input, Button, Popover, Toast } from "@douyinfe/semi-ui";
|
||||
import {
|
||||
@ -11,6 +10,7 @@ import useLayout from "../hooks/useLayout";
|
||||
import useUndoRedo from "../hooks/useUndoRedo";
|
||||
import useSelect from "../hooks/useSelect";
|
||||
import useNotes from "../hooks/useNotes";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function Note({ data, onMouseDown }) {
|
||||
const w = 180;
|
||||
@ -19,7 +19,7 @@ export default function Note({ data, onMouseDown }) {
|
||||
const [editField, setEditField] = useState({});
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const { layout } = useLayout();
|
||||
const { setState } = useContext(StateContext);
|
||||
const { setSaveState } = useSaveState();
|
||||
const { updateNote, deleteNote } = useNotes();
|
||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||
const { selectedElement, setSelectedElement } = useSelect();
|
||||
@ -147,7 +147,7 @@ export default function Note({ data, onMouseDown }) {
|
||||
...prev,
|
||||
open: false,
|
||||
}));
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
stopPropagation
|
||||
content={
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Checkbox,
|
||||
Input,
|
||||
@ -19,27 +19,29 @@ import {
|
||||
IconDeleteStroked,
|
||||
IconCaretdown,
|
||||
} from "@douyinfe/semi-icons";
|
||||
import { StateContext } from "../pages/Editor";
|
||||
import { State } from "../data/data";
|
||||
import useTasks from "../hooks/useTasks";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function Todo() {
|
||||
const Priority = {
|
||||
const Priority = {
|
||||
NONE: 0,
|
||||
LOW: 1,
|
||||
MEDIUM: 2,
|
||||
HIGH: 3,
|
||||
};
|
||||
const SortOrder = {
|
||||
};
|
||||
|
||||
const SortOrder = {
|
||||
ORIGINAL: "My order",
|
||||
PRIORITY: "Priority",
|
||||
COMPLETED: "Completed",
|
||||
ALPHABETICALLY: "Alphabetically",
|
||||
};
|
||||
};
|
||||
|
||||
export default function Todo() {
|
||||
const [activeTask, setActiveTask] = useState(-1);
|
||||
const [, setSortOrder] = useState(SortOrder.ORIGINAL);
|
||||
const { tasks, setTasks, updateTask } = useTasks();
|
||||
const { setState } = useContext(StateContext);
|
||||
const { setSaveState } = useSaveState();
|
||||
|
||||
const priorityLabel = (p) => {
|
||||
switch (p) {
|
||||
@ -165,7 +167,7 @@ export default function Todo() {
|
||||
checked={t.complete}
|
||||
onChange={(e) => {
|
||||
updateTask(i, { complete: e.target.checked });
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
></Checkbox>
|
||||
</Col>
|
||||
@ -174,7 +176,7 @@ export default function Todo() {
|
||||
placeholder="Title"
|
||||
onChange={(v) => updateTask(i, { title: v })}
|
||||
value={t.title}
|
||||
onBlur={() => setState(State.SAVING)}
|
||||
onBlur={() => setSaveState(State.SAVING)}
|
||||
></Input>
|
||||
</Col>
|
||||
<Col span={3}>
|
||||
@ -187,7 +189,7 @@ export default function Todo() {
|
||||
<RadioGroup
|
||||
onChange={(e) => {
|
||||
updateTask(i, { priority: e.target.value });
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
value={t.priority}
|
||||
direction="vertical"
|
||||
@ -222,7 +224,7 @@ export default function Todo() {
|
||||
setTasks((prev) =>
|
||||
prev.filter((task, j) => i !== j)
|
||||
);
|
||||
setState(State.SAVING);
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
@ -245,7 +247,7 @@ export default function Todo() {
|
||||
placeholder="Details"
|
||||
onChange={(v) => updateTask(i, { details: v })}
|
||||
value={t.details}
|
||||
onBlur={() => setState(State.SAVING)}
|
||||
onBlur={() => setSaveState(State.SAVING)}
|
||||
></TextArea>
|
||||
</Col>
|
||||
</Row>
|
||||
|
312
src/components/Workspace.jsx
Normal file
312
src/components/Workspace.jsx
Normal file
@ -0,0 +1,312 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import ControlPanel from "../components/ControlPanel";
|
||||
import Canvas from "../components/Canvas";
|
||||
import SidePanel from "../components/SidePanel";
|
||||
import { State } from "../data/data";
|
||||
import { db } from "../data/db";
|
||||
import useLayout from "../hooks/useLayout";
|
||||
import useSettings from "../hooks/useSettings";
|
||||
import useTransform from "../hooks/useTransform";
|
||||
import useTables from "../hooks/useTables";
|
||||
import useUndoRedo from "../hooks/useUndoRedo";
|
||||
import Controls from "../components/Controls";
|
||||
import useAreas from "../hooks/useAreas";
|
||||
import useNotes from "../hooks/useNotes";
|
||||
import useTypes from "../hooks/useTypes";
|
||||
import useTasks from "../hooks/useTasks";
|
||||
import useSaveState from "../hooks/useSaveState";
|
||||
|
||||
export default function WorkSpace() {
|
||||
const [id, setId] = useState(0);
|
||||
const [title, setTitle] = useState("Untitled Diagram");
|
||||
const [resize, setResize] = useState(false);
|
||||
const [width, setWidth] = useState(340);
|
||||
const [lastSaved, setLastSaved] = useState("");
|
||||
const { layout } = useLayout();
|
||||
const { types, setTypes } = useTypes();
|
||||
const { areas, setAreas } = useAreas();
|
||||
const { tasks, setTasks } = useTasks();
|
||||
const { notes, setNotes } = useNotes();
|
||||
const { settings, setSettings } = useSettings();
|
||||
const { saveState, setSaveState } = useSaveState();
|
||||
const { transform, setTransform } = useTransform();
|
||||
const { tables, relationships, setTables, setRelationships } = useTables();
|
||||
const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo();
|
||||
|
||||
const handleResize = (e) => {
|
||||
if (!resize) return;
|
||||
const w = e.clientX;
|
||||
if (w > 340) setWidth(w);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
tables?.length === 0 &&
|
||||
areas?.length === 0 &&
|
||||
notes?.length === 0 &&
|
||||
types?.length === 0 &&
|
||||
tasks?.length === 0
|
||||
)
|
||||
return;
|
||||
|
||||
if (settings.autosave) {
|
||||
setSaveState(State.SAVING);
|
||||
}
|
||||
}, [
|
||||
undoStack,
|
||||
redoStack,
|
||||
settings.autosave,
|
||||
tables?.length,
|
||||
areas?.length,
|
||||
notes?.length,
|
||||
types?.length,
|
||||
relationships?.length,
|
||||
tasks?.length,
|
||||
transform.zoom,
|
||||
title,
|
||||
setSaveState,
|
||||
]);
|
||||
|
||||
const save = useCallback(
|
||||
async (diagram = true) => {
|
||||
if (saveState !== State.SAVING) {
|
||||
return;
|
||||
}
|
||||
if (diagram) {
|
||||
if (
|
||||
(id === 0 && window.name === "") ||
|
||||
window.name.split(" ")[0] === "lt"
|
||||
) {
|
||||
db.diagrams
|
||||
.add({
|
||||
name: title,
|
||||
lastModified: new Date(),
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
areas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then((id) => {
|
||||
setId(id);
|
||||
window.name = `d ${id}`;
|
||||
setSaveState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
});
|
||||
} else {
|
||||
db.diagrams
|
||||
.update(id, {
|
||||
name: title,
|
||||
lastModified: new Date(),
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
areas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then(() => {
|
||||
setSaveState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
db.templates
|
||||
.update(id, {
|
||||
title: title,
|
||||
tables: tables,
|
||||
relationships: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
subjectAreas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then(() => {
|
||||
setSaveState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
})
|
||||
.catch(() => {
|
||||
setSaveState(State.ERROR);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
tables,
|
||||
relationships,
|
||||
notes,
|
||||
areas,
|
||||
types,
|
||||
title,
|
||||
id,
|
||||
saveState,
|
||||
tasks,
|
||||
transform.zoom,
|
||||
transform.pan,
|
||||
setSaveState,
|
||||
]
|
||||
);
|
||||
useEffect(() => {
|
||||
const name = window.name.split(" ");
|
||||
const op = name[0];
|
||||
const diagram = window.name === "" || op === "d" || op === "lt";
|
||||
|
||||
save(diagram);
|
||||
}, [id, saveState, save]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Editor | drawDB";
|
||||
|
||||
const loadLatestDiagram = async () => {
|
||||
db.diagrams
|
||||
.orderBy("lastModified")
|
||||
.last()
|
||||
.then((d) => {
|
||||
if (d) {
|
||||
setId(d.id);
|
||||
setTables(d.tables);
|
||||
setRelationships(d.references);
|
||||
setNotes(d.notes);
|
||||
setAreas(d.areas);
|
||||
setTypes(d.types);
|
||||
setTasks(d.todos ?? []);
|
||||
setTransform({ pan: d.pan, zoom: d.zoom });
|
||||
window.name = `d ${d.id}`;
|
||||
} else {
|
||||
window.name = "";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const loadDiagram = async (id) => {
|
||||
db.diagrams
|
||||
.get(id)
|
||||
.then((diagram) => {
|
||||
if (diagram) {
|
||||
setId(diagram.id);
|
||||
setTitle(diagram.name);
|
||||
setTables(diagram.tables);
|
||||
setTypes(diagram.types);
|
||||
setRelationships(diagram.references);
|
||||
setAreas(diagram.areas);
|
||||
setNotes(diagram.notes);
|
||||
setTasks(diagram.todos ?? []);
|
||||
setTransform({
|
||||
pan: diagram.pan,
|
||||
zoom: diagram.zoom,
|
||||
});
|
||||
setUndoStack([]);
|
||||
setRedoStack([]);
|
||||
window.name = `d ${diagram.id}`;
|
||||
} else {
|
||||
window.name = "";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const loadTemplate = async (id) => {
|
||||
db.templates
|
||||
.get(id)
|
||||
.then((diagram) => {
|
||||
if (diagram) {
|
||||
setId(diagram.id);
|
||||
setTitle(diagram.title);
|
||||
setTables(diagram.tables);
|
||||
setTypes(diagram.types);
|
||||
setRelationships(diagram.relationships);
|
||||
setAreas(diagram.subjectAreas);
|
||||
setTasks(diagram.todos ?? []);
|
||||
setNotes(diagram.notes);
|
||||
setTransform({
|
||||
zoom: 1,
|
||||
pan: { x: 0, y: 0 },
|
||||
});
|
||||
setUndoStack([]);
|
||||
setRedoStack([]);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
if (window.name == "") {
|
||||
console.log("Loading the latest diagram");
|
||||
loadLatestDiagram();
|
||||
} else {
|
||||
const name = window.name.split(" ");
|
||||
const op = name[0];
|
||||
const did = parseInt(name[1]);
|
||||
switch (op) {
|
||||
case "d": {
|
||||
loadDiagram(did);
|
||||
break;
|
||||
}
|
||||
case "lt": {
|
||||
loadTemplate(did);
|
||||
break;
|
||||
}
|
||||
case "t": {
|
||||
loadTemplate(did);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [
|
||||
setSettings,
|
||||
setTransform,
|
||||
setRedoStack,
|
||||
setUndoStack,
|
||||
setRelationships,
|
||||
setTables,
|
||||
setAreas,
|
||||
setNotes,
|
||||
setTypes,
|
||||
setTasks,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="h-[100vh] flex flex-col overflow-hidden theme">
|
||||
<ControlPanel
|
||||
diagramId={id}
|
||||
setDiagramId={setId}
|
||||
title={title}
|
||||
setTitle={setTitle}
|
||||
lastSaved={lastSaved}
|
||||
setLastSaved={setLastSaved}
|
||||
/>
|
||||
<div
|
||||
className="flex h-full overflow-y-auto"
|
||||
onMouseUp={() => setResize(false)}
|
||||
onMouseLeave={() => setResize(false)}
|
||||
onMouseMove={handleResize}
|
||||
>
|
||||
{layout.sidebar && (
|
||||
<SidePanel resize={resize} setResize={setResize} width={width} />
|
||||
)}
|
||||
<div className="relative w-full h-full overflow-hidden">
|
||||
<Canvas saveState={saveState} setSaveState={setSaveState} />
|
||||
{!(layout.sidebar || layout.toolbar || layout.header) && (
|
||||
<div className="fixed right-5 bottom-4">
|
||||
<Controls />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
14
src/context/SaveStateContext.jsx
Normal file
14
src/context/SaveStateContext.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { createContext, useState } from "react";
|
||||
import { State } from "../data/data";
|
||||
|
||||
export const SaveStateContext = createContext(null);
|
||||
|
||||
export default function SaveStateContextProvider({ children }) {
|
||||
const [saveState, setSaveState] = useState(State.NONE);
|
||||
|
||||
return (
|
||||
<SaveStateContext.Provider value={{ saveState, setSaveState }}>
|
||||
{children}
|
||||
</SaveStateContext.Provider>
|
||||
);
|
||||
}
|
6
src/hooks/useSaveState.js
Normal file
6
src/hooks/useSaveState.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { useContext } from "react";
|
||||
import { SaveStateContext } from "../context/SaveStateContext";
|
||||
|
||||
export default function useSaveState() {
|
||||
return useContext(SaveStateContext);
|
||||
}
|
@ -1,30 +1,14 @@
|
||||
import { useState, createContext, useEffect, useCallback } from "react";
|
||||
import ControlPanel from "../components/ControlPanel";
|
||||
import Canvas from "../components/Canvas";
|
||||
import SidePanel from "../components/SidePanel";
|
||||
import { State } from "../data/data";
|
||||
import { db } from "../data/db";
|
||||
import useLayout from "../hooks/useLayout";
|
||||
import LayoutContextProvider from "../context/LayoutContext";
|
||||
import useSettings from "../hooks/useSettings";
|
||||
import TransformContextProvider from "../context/TransformContext";
|
||||
import useTransform from "../hooks/useTransform";
|
||||
import useTables from "../hooks/useTables";
|
||||
import TablesContextProvider from "../context/TablesContext";
|
||||
import useUndoRedo from "../hooks/useUndoRedo";
|
||||
import UndoRedoContextProvider from "../context/UndoRedoContext";
|
||||
import SelectContextProvider from "../context/SelectContext";
|
||||
import AreasContextProvider from "../context/AreasContext";
|
||||
import Controls from "../components/Controls";
|
||||
import useAreas from "../hooks/useAreas";
|
||||
import useNotes from "../hooks/useNotes";
|
||||
import NotesContextProvider from "../context/NotesContext";
|
||||
import useTypes from "../hooks/useTypes";
|
||||
import TypesContextProvider from "../context/TypesContext";
|
||||
import useTasks from "../hooks/useTasks";
|
||||
import TasksContextProvider from "../context/TasksContext";
|
||||
|
||||
export const StateContext = createContext();
|
||||
import SaveStateContextProvider from "../context/SaveStateContext";
|
||||
import WorkSpace from "../components/Workspace";
|
||||
|
||||
export default function Editor() {
|
||||
return (
|
||||
@ -37,7 +21,9 @@ export default function Editor() {
|
||||
<NotesContextProvider>
|
||||
<TypesContextProvider>
|
||||
<TablesContextProvider>
|
||||
<SaveStateContextProvider>
|
||||
<WorkSpace />
|
||||
</SaveStateContextProvider>
|
||||
</TablesContextProvider>
|
||||
</TypesContextProvider>
|
||||
</NotesContextProvider>
|
||||
@ -49,298 +35,3 @@ export default function Editor() {
|
||||
</LayoutContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function WorkSpace() {
|
||||
const [id, setId] = useState(0);
|
||||
const [title, setTitle] = useState("Untitled Diagram");
|
||||
const [state, setState] = useState(State.NONE);
|
||||
const [lastSaved, setLastSaved] = useState("");
|
||||
const { types, setTypes } = useTypes();
|
||||
const [resize, setResize] = useState(false);
|
||||
const [width, setWidth] = useState(340);
|
||||
const { tasks, setTasks } = useTasks();
|
||||
const { layout } = useLayout();
|
||||
const { areas, setAreas } = useAreas();
|
||||
const { settings, setSettings } = useSettings();
|
||||
const { notes, setNotes } = useNotes();
|
||||
const { transform, setTransform } = useTransform();
|
||||
const { tables, relationships, setTables, setRelationships } = useTables();
|
||||
const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo();
|
||||
|
||||
const handleResize = (e) => {
|
||||
if (!resize) return;
|
||||
const w = e.clientX;
|
||||
if (w > 340) setWidth(w);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
tables?.length === 0 &&
|
||||
areas?.length === 0 &&
|
||||
notes?.length === 0 &&
|
||||
types?.length === 0 &&
|
||||
tasks?.length === 0
|
||||
)
|
||||
return;
|
||||
|
||||
if (settings.autosave) {
|
||||
setState(State.SAVING);
|
||||
}
|
||||
}, [
|
||||
undoStack,
|
||||
redoStack,
|
||||
settings.autosave,
|
||||
tables?.length,
|
||||
areas?.length,
|
||||
notes?.length,
|
||||
types?.length,
|
||||
relationships?.length,
|
||||
tasks?.length,
|
||||
transform.zoom,
|
||||
title,
|
||||
]);
|
||||
|
||||
const save = useCallback(
|
||||
async (diagram = true) => {
|
||||
if (state !== State.SAVING) {
|
||||
return;
|
||||
}
|
||||
if (diagram) {
|
||||
if (
|
||||
(id === 0 && window.name === "") ||
|
||||
window.name.split(" ")[0] === "lt"
|
||||
) {
|
||||
db.diagrams
|
||||
.add({
|
||||
name: title,
|
||||
lastModified: new Date(),
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
areas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then((id) => {
|
||||
setId(id);
|
||||
window.name = `d ${id}`;
|
||||
setState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
});
|
||||
} else {
|
||||
db.diagrams
|
||||
.update(id, {
|
||||
name: title,
|
||||
lastModified: new Date(),
|
||||
tables: tables,
|
||||
references: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
areas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then(() => {
|
||||
setState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
db.templates
|
||||
.update(id, {
|
||||
title: title,
|
||||
tables: tables,
|
||||
relationships: relationships,
|
||||
types: types,
|
||||
notes: notes,
|
||||
subjectAreas: areas,
|
||||
todos: tasks,
|
||||
pan: transform.pan,
|
||||
zoom: transform.zoom,
|
||||
})
|
||||
.then(() => {
|
||||
setState(State.SAVED);
|
||||
setLastSaved(new Date().toLocaleString());
|
||||
})
|
||||
.catch(() => {
|
||||
setState(State.ERROR);
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
tables,
|
||||
relationships,
|
||||
notes,
|
||||
areas,
|
||||
types,
|
||||
title,
|
||||
id,
|
||||
state,
|
||||
tasks,
|
||||
transform.zoom,
|
||||
transform.pan,
|
||||
]
|
||||
);
|
||||
useEffect(() => {
|
||||
const name = window.name.split(" ");
|
||||
const op = name[0];
|
||||
const diagram = window.name === "" || op === "d" || op === "lt";
|
||||
|
||||
save(diagram);
|
||||
}, [id, state, save]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Editor | drawDB";
|
||||
|
||||
const loadLatestDiagram = async () => {
|
||||
db.diagrams
|
||||
.orderBy("lastModified")
|
||||
.last()
|
||||
.then((d) => {
|
||||
if (d) {
|
||||
setId(d.id);
|
||||
setTables(d.tables);
|
||||
setRelationships(d.references);
|
||||
setNotes(d.notes);
|
||||
setAreas(d.areas);
|
||||
setTypes(d.types);
|
||||
setTasks(d.todos ?? []);
|
||||
setTransform({ pan: d.pan, zoom: d.zoom });
|
||||
window.name = `d ${d.id}`;
|
||||
} else {
|
||||
window.name = "";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const loadDiagram = async (id) => {
|
||||
db.diagrams
|
||||
.get(id)
|
||||
.then((diagram) => {
|
||||
if (diagram) {
|
||||
setId(diagram.id);
|
||||
setTitle(diagram.name);
|
||||
setTables(diagram.tables);
|
||||
setTypes(diagram.types);
|
||||
setRelationships(diagram.references);
|
||||
setAreas(diagram.areas);
|
||||
setNotes(diagram.notes);
|
||||
setTasks(diagram.todos ?? []);
|
||||
setTransform({
|
||||
pan: diagram.pan,
|
||||
zoom: diagram.zoom,
|
||||
});
|
||||
setUndoStack([]);
|
||||
setRedoStack([]);
|
||||
window.name = `d ${diagram.id}`;
|
||||
} else {
|
||||
window.name = "";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
const loadTemplate = async (id) => {
|
||||
db.templates
|
||||
.get(id)
|
||||
.then((diagram) => {
|
||||
if (diagram) {
|
||||
setId(diagram.id);
|
||||
setTitle(diagram.title);
|
||||
setTables(diagram.tables);
|
||||
setTypes(diagram.types);
|
||||
setRelationships(diagram.relationships);
|
||||
setAreas(diagram.subjectAreas);
|
||||
setTasks(diagram.todos ?? []);
|
||||
setNotes(diagram.notes);
|
||||
setTransform({
|
||||
zoom: 1,
|
||||
pan: { x: 0, y: 0 },
|
||||
});
|
||||
setUndoStack([]);
|
||||
setRedoStack([]);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
if (window.name == "") {
|
||||
console.log("Loading the latest diagram");
|
||||
loadLatestDiagram();
|
||||
} else {
|
||||
const name = window.name.split(" ");
|
||||
const op = name[0];
|
||||
const did = parseInt(name[1]);
|
||||
switch (op) {
|
||||
case "d": {
|
||||
loadDiagram(did);
|
||||
break;
|
||||
}
|
||||
case "lt": {
|
||||
loadTemplate(did);
|
||||
break;
|
||||
}
|
||||
case "t": {
|
||||
loadTemplate(did);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [
|
||||
setSettings,
|
||||
setTransform,
|
||||
setRedoStack,
|
||||
setUndoStack,
|
||||
setRelationships,
|
||||
setTables,
|
||||
setAreas,
|
||||
setNotes,
|
||||
setTypes,
|
||||
setTasks,
|
||||
]);
|
||||
|
||||
return (
|
||||
<StateContext.Provider value={{ state, setState }}>
|
||||
<div className="h-[100vh] flex flex-col overflow-hidden theme">
|
||||
<ControlPanel
|
||||
diagramId={id}
|
||||
setDiagramId={setId}
|
||||
title={title}
|
||||
setTitle={setTitle}
|
||||
lastSaved={lastSaved}
|
||||
setLastSaved={setLastSaved}
|
||||
/>
|
||||
<div
|
||||
className="flex h-full overflow-y-auto"
|
||||
onMouseUp={() => setResize(false)}
|
||||
onMouseLeave={() => setResize(false)}
|
||||
onMouseMove={handleResize}
|
||||
>
|
||||
{layout.sidebar && (
|
||||
<SidePanel resize={resize} setResize={setResize} width={width} />
|
||||
)}
|
||||
<div className="relative w-full h-full overflow-hidden">
|
||||
<Canvas state={state} setState={setState} />
|
||||
{!(layout.sidebar || layout.toolbar || layout.header) && (
|
||||
<div className="fixed right-5 bottom-4">
|
||||
<Controls />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StateContext.Provider>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user