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 { Button, Popover, Input, Toast } from "@douyinfe/semi-ui";
|
||||||
import {
|
import {
|
||||||
IconEdit,
|
IconEdit,
|
||||||
@ -13,19 +13,19 @@ import {
|
|||||||
defaultTableTheme,
|
defaultTableTheme,
|
||||||
State,
|
State,
|
||||||
} from "../data/data";
|
} from "../data/data";
|
||||||
import { StateContext } from "../pages/Editor";
|
|
||||||
import useLayout from "../hooks/useLayout";
|
import useLayout from "../hooks/useLayout";
|
||||||
import useSettings from "../hooks/useSettings";
|
import useSettings from "../hooks/useSettings";
|
||||||
import useUndoRedo from "../hooks/useUndoRedo";
|
import useUndoRedo from "../hooks/useUndoRedo";
|
||||||
import useSelect from "../hooks/useSelect";
|
import useSelect from "../hooks/useSelect";
|
||||||
import useAreas from "../hooks/useAreas";
|
import useAreas from "../hooks/useAreas";
|
||||||
|
import useSaveState from "../hooks/useSaveState";
|
||||||
|
|
||||||
export default function Area(props) {
|
export default function Area(props) {
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
const [editField, setEditField] = useState({});
|
const [editField, setEditField] = useState({});
|
||||||
const { setState } = useContext(StateContext);
|
|
||||||
const { layout } = useLayout();
|
const { layout } = useLayout();
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
|
const { setSaveState } = useSaveState();
|
||||||
const { updateArea, deleteArea } = useAreas();
|
const { updateArea, deleteArea } = useAreas();
|
||||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||||
const { selectedElement, setSelectedElement } = useSelect();
|
const { selectedElement, setSelectedElement } = useSelect();
|
||||||
@ -100,7 +100,7 @@ export default function Area(props) {
|
|||||||
...prev,
|
...prev,
|
||||||
open: false,
|
open: false,
|
||||||
}));
|
}));
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
stopPropagation
|
stopPropagation
|
||||||
content={
|
content={
|
||||||
@ -145,7 +145,7 @@ export default function Area(props) {
|
|||||||
updateArea(props.areaData.id, {
|
updateArea(props.areaData.id, {
|
||||||
color: defaultTableTheme,
|
color: defaultTableTheme,
|
||||||
});
|
});
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Empty,
|
Empty,
|
||||||
Row,
|
Row,
|
||||||
@ -26,12 +26,12 @@ import {
|
|||||||
ObjectType,
|
ObjectType,
|
||||||
State,
|
State,
|
||||||
} from "../data/data";
|
} from "../data/data";
|
||||||
import { StateContext } from "../pages/Editor";
|
|
||||||
import useUndoRedo from "../hooks/useUndoRedo";
|
import useUndoRedo from "../hooks/useUndoRedo";
|
||||||
import useAreas from "../hooks/useAreas";
|
import useAreas from "../hooks/useAreas";
|
||||||
|
import useSaveState from "../hooks/useSaveState";
|
||||||
|
|
||||||
export default function AreaOverview() {
|
export default function AreaOverview() {
|
||||||
const { setState } = useContext(StateContext);
|
const { setSaveState } = useSaveState();
|
||||||
const { areas, addArea, deleteArea, updateArea } = useAreas();
|
const { areas, addArea, deleteArea, updateArea } = useAreas();
|
||||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||||
const [editField, setEditField] = useState({});
|
const [editField, setEditField] = useState({});
|
||||||
@ -141,7 +141,7 @@ export default function AreaOverview() {
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateArea(i, { color: defaultTableTheme });
|
updateArea(i, { color: defaultTableTheme });
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
IconCaretdown,
|
IconCaretdown,
|
||||||
IconChevronRight,
|
IconChevronRight,
|
||||||
@ -43,7 +43,6 @@ import {
|
|||||||
jsonToMariaDB,
|
jsonToMariaDB,
|
||||||
jsonToSQLServer,
|
jsonToSQLServer,
|
||||||
} from "../utils/toSQL";
|
} from "../utils/toSQL";
|
||||||
import { StateContext } from "../pages/Editor";
|
|
||||||
import { IconAddTable, IconAddArea, IconAddNote } from "./CustomIcons";
|
import { IconAddTable, IconAddArea, IconAddNote } from "./CustomIcons";
|
||||||
import { ObjectType, Action, Tab, State, Cardinality } from "../data/data";
|
import { ObjectType, Action, Tab, State, Cardinality } from "../data/data";
|
||||||
import jsPDF from "jspdf";
|
import jsPDF from "jspdf";
|
||||||
@ -68,6 +67,7 @@ import { dataURItoBlob } from "../utils/utils";
|
|||||||
import useAreas from "../hooks/useAreas";
|
import useAreas from "../hooks/useAreas";
|
||||||
import useNotes from "../hooks/useNotes";
|
import useNotes from "../hooks/useNotes";
|
||||||
import useTypes from "../hooks/useTypes";
|
import useTypes from "../hooks/useTypes";
|
||||||
|
import useSaveState from "../hooks/useSaveState";
|
||||||
|
|
||||||
export default function ControlPanel({
|
export default function ControlPanel({
|
||||||
diagramId,
|
diagramId,
|
||||||
@ -117,7 +117,7 @@ export default function ControlPanel({
|
|||||||
message: "",
|
message: "",
|
||||||
});
|
});
|
||||||
const [data, setData] = useState(null);
|
const [data, setData] = useState(null);
|
||||||
const { state, setState } = useContext(StateContext);
|
const { saveState, setSaveState } = useSaveState();
|
||||||
const { layout, setLayout } = useLayout();
|
const { layout, setLayout } = useLayout();
|
||||||
const { settings, setSettings } = useSettings();
|
const { settings, setSettings } = useSettings();
|
||||||
const {
|
const {
|
||||||
@ -734,7 +734,7 @@ export default function ControlPanel({
|
|||||||
copy();
|
copy();
|
||||||
del();
|
del();
|
||||||
};
|
};
|
||||||
const save = () => setState(State.SAVING);
|
const save = () => setSaveState(State.SAVING);
|
||||||
const open = () => setVisible(MODAL.OPEN);
|
const open = () => setVisible(MODAL.OPEN);
|
||||||
const saveDiagramAs = () => setVisible(MODAL.SAVEAS);
|
const saveDiagramAs = () => setVisible(MODAL.SAVEAS);
|
||||||
const loadDiagram = async (id) => {
|
const loadDiagram = async (id) => {
|
||||||
@ -1036,7 +1036,7 @@ export default function ControlPanel({
|
|||||||
Exit: {
|
Exit: {
|
||||||
function: () => {
|
function: () => {
|
||||||
save();
|
save();
|
||||||
if (state === State.SAVED) navigate("/");
|
if (saveState === State.SAVED) navigate("/");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2256,7 +2256,7 @@ export default function ControlPanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getState() {
|
function getState() {
|
||||||
switch (state) {
|
switch (saveState) {
|
||||||
case State.NONE:
|
case State.NONE:
|
||||||
return "No changes";
|
return "No changes";
|
||||||
case State.LOADING:
|
case State.LOADING:
|
||||||
@ -2378,7 +2378,7 @@ export default function ControlPanel({
|
|||||||
size="small"
|
size="small"
|
||||||
type="tertiary"
|
type="tertiary"
|
||||||
icon={
|
icon={
|
||||||
state === State.LOADING || state === State.SAVING ? (
|
saveState === State.LOADING || saveState === State.SAVING ? (
|
||||||
<Spin size="small" />
|
<Spin size="small" />
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { useContext, useState } from "react";
|
import { useState } from "react";
|
||||||
import { StateContext } from "../pages/Editor";
|
|
||||||
import { Action, ObjectType, noteThemes, Tab, State } from "../data/data";
|
import { Action, ObjectType, noteThemes, Tab, State } from "../data/data";
|
||||||
import { Input, Button, Popover, Toast } from "@douyinfe/semi-ui";
|
import { Input, Button, Popover, Toast } from "@douyinfe/semi-ui";
|
||||||
import {
|
import {
|
||||||
@ -11,6 +10,7 @@ import useLayout from "../hooks/useLayout";
|
|||||||
import useUndoRedo from "../hooks/useUndoRedo";
|
import useUndoRedo from "../hooks/useUndoRedo";
|
||||||
import useSelect from "../hooks/useSelect";
|
import useSelect from "../hooks/useSelect";
|
||||||
import useNotes from "../hooks/useNotes";
|
import useNotes from "../hooks/useNotes";
|
||||||
|
import useSaveState from "../hooks/useSaveState";
|
||||||
|
|
||||||
export default function Note({ data, onMouseDown }) {
|
export default function Note({ data, onMouseDown }) {
|
||||||
const w = 180;
|
const w = 180;
|
||||||
@ -19,7 +19,7 @@ export default function Note({ data, onMouseDown }) {
|
|||||||
const [editField, setEditField] = useState({});
|
const [editField, setEditField] = useState({});
|
||||||
const [hovered, setHovered] = useState(false);
|
const [hovered, setHovered] = useState(false);
|
||||||
const { layout } = useLayout();
|
const { layout } = useLayout();
|
||||||
const { setState } = useContext(StateContext);
|
const { setSaveState } = useSaveState();
|
||||||
const { updateNote, deleteNote } = useNotes();
|
const { updateNote, deleteNote } = useNotes();
|
||||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||||
const { selectedElement, setSelectedElement } = useSelect();
|
const { selectedElement, setSelectedElement } = useSelect();
|
||||||
@ -147,7 +147,7 @@ export default function Note({ data, onMouseDown }) {
|
|||||||
...prev,
|
...prev,
|
||||||
open: false,
|
open: false,
|
||||||
}));
|
}));
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
stopPropagation
|
stopPropagation
|
||||||
content={
|
content={
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useContext, useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Input,
|
Input,
|
||||||
@ -19,27 +19,29 @@ import {
|
|||||||
IconDeleteStroked,
|
IconDeleteStroked,
|
||||||
IconCaretdown,
|
IconCaretdown,
|
||||||
} from "@douyinfe/semi-icons";
|
} from "@douyinfe/semi-icons";
|
||||||
import { StateContext } from "../pages/Editor";
|
|
||||||
import { State } from "../data/data";
|
import { State } from "../data/data";
|
||||||
import useTasks from "../hooks/useTasks";
|
import useTasks from "../hooks/useTasks";
|
||||||
|
import useSaveState from "../hooks/useSaveState";
|
||||||
|
|
||||||
|
const Priority = {
|
||||||
|
NONE: 0,
|
||||||
|
LOW: 1,
|
||||||
|
MEDIUM: 2,
|
||||||
|
HIGH: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SortOrder = {
|
||||||
|
ORIGINAL: "My order",
|
||||||
|
PRIORITY: "Priority",
|
||||||
|
COMPLETED: "Completed",
|
||||||
|
ALPHABETICALLY: "Alphabetically",
|
||||||
|
};
|
||||||
|
|
||||||
export default function Todo() {
|
export default function Todo() {
|
||||||
const Priority = {
|
|
||||||
NONE: 0,
|
|
||||||
LOW: 1,
|
|
||||||
MEDIUM: 2,
|
|
||||||
HIGH: 3,
|
|
||||||
};
|
|
||||||
const SortOrder = {
|
|
||||||
ORIGINAL: "My order",
|
|
||||||
PRIORITY: "Priority",
|
|
||||||
COMPLETED: "Completed",
|
|
||||||
ALPHABETICALLY: "Alphabetically",
|
|
||||||
};
|
|
||||||
const [activeTask, setActiveTask] = useState(-1);
|
const [activeTask, setActiveTask] = useState(-1);
|
||||||
const [, setSortOrder] = useState(SortOrder.ORIGINAL);
|
const [, setSortOrder] = useState(SortOrder.ORIGINAL);
|
||||||
const { tasks, setTasks, updateTask } = useTasks();
|
const { tasks, setTasks, updateTask } = useTasks();
|
||||||
const { setState } = useContext(StateContext);
|
const { setSaveState } = useSaveState();
|
||||||
|
|
||||||
const priorityLabel = (p) => {
|
const priorityLabel = (p) => {
|
||||||
switch (p) {
|
switch (p) {
|
||||||
@ -165,7 +167,7 @@ export default function Todo() {
|
|||||||
checked={t.complete}
|
checked={t.complete}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
updateTask(i, { complete: e.target.checked });
|
updateTask(i, { complete: e.target.checked });
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
></Checkbox>
|
></Checkbox>
|
||||||
</Col>
|
</Col>
|
||||||
@ -174,7 +176,7 @@ export default function Todo() {
|
|||||||
placeholder="Title"
|
placeholder="Title"
|
||||||
onChange={(v) => updateTask(i, { title: v })}
|
onChange={(v) => updateTask(i, { title: v })}
|
||||||
value={t.title}
|
value={t.title}
|
||||||
onBlur={() => setState(State.SAVING)}
|
onBlur={() => setSaveState(State.SAVING)}
|
||||||
></Input>
|
></Input>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={3}>
|
<Col span={3}>
|
||||||
@ -187,7 +189,7 @@ export default function Todo() {
|
|||||||
<RadioGroup
|
<RadioGroup
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
updateTask(i, { priority: e.target.value });
|
updateTask(i, { priority: e.target.value });
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
value={t.priority}
|
value={t.priority}
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
@ -222,7 +224,7 @@ export default function Todo() {
|
|||||||
setTasks((prev) =>
|
setTasks((prev) =>
|
||||||
prev.filter((task, j) => i !== j)
|
prev.filter((task, j) => i !== j)
|
||||||
);
|
);
|
||||||
setState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
@ -245,7 +247,7 @@ export default function Todo() {
|
|||||||
placeholder="Details"
|
placeholder="Details"
|
||||||
onChange={(v) => updateTask(i, { details: v })}
|
onChange={(v) => updateTask(i, { details: v })}
|
||||||
value={t.details}
|
value={t.details}
|
||||||
onBlur={() => setState(State.SAVING)}
|
onBlur={() => setSaveState(State.SAVING)}
|
||||||
></TextArea>
|
></TextArea>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</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 LayoutContextProvider from "../context/LayoutContext";
|
||||||
import useSettings from "../hooks/useSettings";
|
|
||||||
import TransformContextProvider from "../context/TransformContext";
|
import TransformContextProvider from "../context/TransformContext";
|
||||||
import useTransform from "../hooks/useTransform";
|
|
||||||
import useTables from "../hooks/useTables";
|
|
||||||
import TablesContextProvider from "../context/TablesContext";
|
import TablesContextProvider from "../context/TablesContext";
|
||||||
import useUndoRedo from "../hooks/useUndoRedo";
|
|
||||||
import UndoRedoContextProvider from "../context/UndoRedoContext";
|
import UndoRedoContextProvider from "../context/UndoRedoContext";
|
||||||
import SelectContextProvider from "../context/SelectContext";
|
import SelectContextProvider from "../context/SelectContext";
|
||||||
import AreasContextProvider from "../context/AreasContext";
|
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 NotesContextProvider from "../context/NotesContext";
|
||||||
import useTypes from "../hooks/useTypes";
|
|
||||||
import TypesContextProvider from "../context/TypesContext";
|
import TypesContextProvider from "../context/TypesContext";
|
||||||
import useTasks from "../hooks/useTasks";
|
|
||||||
import TasksContextProvider from "../context/TasksContext";
|
import TasksContextProvider from "../context/TasksContext";
|
||||||
|
import SaveStateContextProvider from "../context/SaveStateContext";
|
||||||
export const StateContext = createContext();
|
import WorkSpace from "../components/Workspace";
|
||||||
|
|
||||||
export default function Editor() {
|
export default function Editor() {
|
||||||
return (
|
return (
|
||||||
@ -37,7 +21,9 @@ export default function Editor() {
|
|||||||
<NotesContextProvider>
|
<NotesContextProvider>
|
||||||
<TypesContextProvider>
|
<TypesContextProvider>
|
||||||
<TablesContextProvider>
|
<TablesContextProvider>
|
||||||
<WorkSpace />
|
<SaveStateContextProvider>
|
||||||
|
<WorkSpace />
|
||||||
|
</SaveStateContextProvider>
|
||||||
</TablesContextProvider>
|
</TablesContextProvider>
|
||||||
</TypesContextProvider>
|
</TypesContextProvider>
|
||||||
</NotesContextProvider>
|
</NotesContextProvider>
|
||||||
@ -49,298 +35,3 @@ export default function Editor() {
|
|||||||
</LayoutContextProvider>
|
</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