Move controlpanel modal and sidesheet into folders
This commit is contained in:
parent
1576b3fb96
commit
173b02daa2
File diff suppressed because it is too large
Load Diff
71
src/components/EditorHeader/LayoutDropdown.jsx
Normal file
71
src/components/EditorHeader/LayoutDropdown.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import {
|
||||||
|
IconCaretdown,
|
||||||
|
IconCheckboxTick,
|
||||||
|
IconRowsStroked,
|
||||||
|
} from "@douyinfe/semi-icons";
|
||||||
|
import { Dropdown } from "@douyinfe/semi-ui";
|
||||||
|
import { useLayout } from "../../hooks";
|
||||||
|
import { enterFullscreen, exitFullscreen } from "../../utils/fullscreen";
|
||||||
|
|
||||||
|
export default function LayoutDropdown() {
|
||||||
|
const { layout, setLayout } = useLayout();
|
||||||
|
const invertLayout = (component) =>
|
||||||
|
setLayout((prev) => ({ ...prev, [component]: !prev[component] }));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
position="bottomLeft"
|
||||||
|
style={{ width: "180px" }}
|
||||||
|
render={
|
||||||
|
<Dropdown.Menu>
|
||||||
|
<Dropdown.Item
|
||||||
|
icon={
|
||||||
|
layout.header ? <IconCheckboxTick /> : <div className="px-2" />
|
||||||
|
}
|
||||||
|
onClick={() => invertLayout("header")}
|
||||||
|
>
|
||||||
|
Header
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item
|
||||||
|
icon={
|
||||||
|
layout.sidebar ? <IconCheckboxTick /> : <div className="px-2" />
|
||||||
|
}
|
||||||
|
onClick={() => invertLayout("sidebar")}
|
||||||
|
>
|
||||||
|
Sidebar
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item
|
||||||
|
icon={
|
||||||
|
layout.issues ? <IconCheckboxTick /> : <div className="px-2" />
|
||||||
|
}
|
||||||
|
onClick={() => invertLayout("issues")}
|
||||||
|
>
|
||||||
|
Issues
|
||||||
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Divider />
|
||||||
|
<Dropdown.Item
|
||||||
|
icon={<div className="px-2" />}
|
||||||
|
onClick={() => {
|
||||||
|
if (layout.fullscreen) {
|
||||||
|
exitFullscreen();
|
||||||
|
} else {
|
||||||
|
enterFullscreen();
|
||||||
|
}
|
||||||
|
invertLayout("fullscreen");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Fullscreen
|
||||||
|
</Dropdown.Item>
|
||||||
|
</Dropdown.Menu>
|
||||||
|
}
|
||||||
|
trigger="click"
|
||||||
|
>
|
||||||
|
<div className="py-1 px-2 hover-2 rounded flex items-center justify-center">
|
||||||
|
<IconRowsStroked size="extra-large" />
|
||||||
|
<div>
|
||||||
|
<IconCaretdown />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
127
src/components/EditorHeader/Modal/ImportDiagram.jsx
Normal file
127
src/components/EditorHeader/Modal/ImportDiagram.jsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {
|
||||||
|
ddbDiagramIsValid,
|
||||||
|
jsonDiagramIsValid,
|
||||||
|
} from "../../../utils/validateSchema";
|
||||||
|
import { Upload, Banner } from "@douyinfe/semi-ui";
|
||||||
|
import { STATUS } from "../../../data/constants";
|
||||||
|
import { useAreas, useNotes, useTables } from "../../../hooks";
|
||||||
|
|
||||||
|
export default function ImportDiagram({ setImportData, error, setError }) {
|
||||||
|
const { areas } = useAreas();
|
||||||
|
const { notes } = useNotes();
|
||||||
|
const { tables, relationships } = useTables();
|
||||||
|
|
||||||
|
const diagramIsEmpty = () => {
|
||||||
|
return (
|
||||||
|
tables.length === 0 &&
|
||||||
|
relationships.length === 0 &&
|
||||||
|
notes.length === 0 &&
|
||||||
|
areas.length === 0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Upload
|
||||||
|
action="#"
|
||||||
|
beforeUpload={({ file, fileList }) => {
|
||||||
|
const f = fileList[0].fileInstance;
|
||||||
|
if (!f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
let jsonObject = null;
|
||||||
|
try {
|
||||||
|
jsonObject = JSON.parse(e.target.result);
|
||||||
|
} catch (error) {
|
||||||
|
setError({
|
||||||
|
type: STATUS.ERROR,
|
||||||
|
message: "The file contains an error.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (f.type === "application/json") {
|
||||||
|
if (!jsonDiagramIsValid(jsonObject)) {
|
||||||
|
setError({
|
||||||
|
type: STATUS.ERROR,
|
||||||
|
message:
|
||||||
|
"The file is missing necessary properties for a diagram.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (f.name.split(".").pop() === "ddb") {
|
||||||
|
if (!ddbDiagramIsValid(jsonObject)) {
|
||||||
|
setError({
|
||||||
|
type: STATUS.ERROR,
|
||||||
|
message:
|
||||||
|
"The file is missing necessary properties for a diagram.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setImportData(jsonObject);
|
||||||
|
if (diagramIsEmpty()) {
|
||||||
|
setError({
|
||||||
|
type: STATUS.OK,
|
||||||
|
message: "Everything looks good. You can now import.",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setError({
|
||||||
|
type: STATUS.WARNING,
|
||||||
|
message:
|
||||||
|
"The current diagram is not empty. Importing a new diagram will overwrite the current changes.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(f);
|
||||||
|
|
||||||
|
return {
|
||||||
|
autoRemove: false,
|
||||||
|
fileInstance: file.fileInstance,
|
||||||
|
status: "success",
|
||||||
|
shouldUpload: false,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
draggable={true}
|
||||||
|
dragMainText="Drag and drop the file here or click to upload."
|
||||||
|
dragSubText="Support json and ddb"
|
||||||
|
accept="application/json,.ddb"
|
||||||
|
onRemove={() =>
|
||||||
|
setError({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onFileChange={() =>
|
||||||
|
setError({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
limit={1}
|
||||||
|
/>
|
||||||
|
{error.type === STATUS.ERROR ? (
|
||||||
|
<Banner
|
||||||
|
type="danger"
|
||||||
|
fullMode={false}
|
||||||
|
description={<div>{error.message}</div>}
|
||||||
|
/>
|
||||||
|
) : error.type === STATUS.OK ? (
|
||||||
|
<Banner
|
||||||
|
type="info"
|
||||||
|
fullMode={false}
|
||||||
|
description={<div>{error.message}</div>}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
error.type === STATUS.WARNING && (
|
||||||
|
<Banner
|
||||||
|
type="warning"
|
||||||
|
fullMode={false}
|
||||||
|
description={<div>{error.message}</div>}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
66
src/components/EditorHeader/Modal/ImportSource.jsx
Normal file
66
src/components/EditorHeader/Modal/ImportSource.jsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { Upload, Checkbox } from "@douyinfe/semi-ui";
|
||||||
|
import { STATUS } from "../../../data/constants";
|
||||||
|
|
||||||
|
export default function ImportSource({ importData, setImportData, setError }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Upload
|
||||||
|
action="#"
|
||||||
|
beforeUpload={({ file, fileList }) => {
|
||||||
|
const f = fileList[0].fileInstance;
|
||||||
|
if (!f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
setImportData((prev) => ({ ...prev, src: e.target.result }));
|
||||||
|
};
|
||||||
|
reader.readAsText(f);
|
||||||
|
|
||||||
|
return {
|
||||||
|
autoRemove: false,
|
||||||
|
fileInstance: file.fileInstance,
|
||||||
|
status: "success",
|
||||||
|
shouldUpload: false,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
draggable={true}
|
||||||
|
dragMainText="Drag and drop the file here or click to upload."
|
||||||
|
dragSubText="Upload an sql file to autogenerate your tables and columns."
|
||||||
|
accept=".sql"
|
||||||
|
onRemove={() => {
|
||||||
|
setError({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
setImportData((prev) => ({ ...prev, src: "" }));
|
||||||
|
}}
|
||||||
|
onFileChange={() =>
|
||||||
|
setError({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
limit={1}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div className="text-xs mb-3 mt-1 opacity-80">
|
||||||
|
* For the time being loading only MySQL scripts is supported.
|
||||||
|
</div>
|
||||||
|
<Checkbox
|
||||||
|
aria-label="overwrite checkbox"
|
||||||
|
checked={importData.overwrite}
|
||||||
|
defaultChecked
|
||||||
|
onChange={(e) =>
|
||||||
|
setImportData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
overwrite: e.target.checked,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Overwrite existing diagram
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
312
src/components/EditorHeader/Modal/Modal.jsx
Normal file
312
src/components/EditorHeader/Modal/Modal.jsx
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
import {
|
||||||
|
Spin,
|
||||||
|
Input,
|
||||||
|
Image,
|
||||||
|
Toast,
|
||||||
|
Modal as SemiUIModal,
|
||||||
|
} from "@douyinfe/semi-ui";
|
||||||
|
import { MODAL, STATUS } from "../../../data/constants";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { db } from "../../../data/db";
|
||||||
|
import {
|
||||||
|
useAreas,
|
||||||
|
useNotes,
|
||||||
|
useSettings,
|
||||||
|
useTables,
|
||||||
|
useTransform,
|
||||||
|
useTypes,
|
||||||
|
useUndoRedo,
|
||||||
|
} from "../../../hooks";
|
||||||
|
import { saveAs } from "file-saver";
|
||||||
|
import { Parser } from "node-sql-parser";
|
||||||
|
import { astToDiagram } from "../../../utils/astToDiagram";
|
||||||
|
import { getModalTitle, getOkText } from "../../../utils/modalTitles";
|
||||||
|
import Rename from "./Rename";
|
||||||
|
import Open from "./Open";
|
||||||
|
import New from "./New";
|
||||||
|
import ImportDiagram from "./ImportDiagram";
|
||||||
|
import ImportSource from "./ImportSource";
|
||||||
|
import Editor from "@monaco-editor/react";
|
||||||
|
|
||||||
|
export default function Modal({
|
||||||
|
modal,
|
||||||
|
setModal,
|
||||||
|
title,
|
||||||
|
setTitle,
|
||||||
|
prevTitle,
|
||||||
|
setPrevTitle,
|
||||||
|
setDiagramId,
|
||||||
|
exportData,
|
||||||
|
setExportData,
|
||||||
|
}) {
|
||||||
|
const { setTables, setRelationships } = useTables();
|
||||||
|
const { setNotes } = useNotes();
|
||||||
|
const { setAreas } = useAreas();
|
||||||
|
const { setTypes } = useTypes();
|
||||||
|
const { settings } = useSettings();
|
||||||
|
const { setTransform } = useTransform();
|
||||||
|
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||||
|
const [importSource, setImportSource] = useState({
|
||||||
|
src: "",
|
||||||
|
overwrite: true,
|
||||||
|
dbms: "MySQL",
|
||||||
|
});
|
||||||
|
const [importData, setImportData] = useState(null);
|
||||||
|
const [error, setError] = useState({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
const [selectedTemplateId, setSelectedTemplateId] = useState(-1);
|
||||||
|
const [selectedDiagramId, setSelectedDiagramId] = useState(0);
|
||||||
|
const [saveAsTitle, setSaveAsTitle] = useState(title);
|
||||||
|
|
||||||
|
const overwriteDiagram = () => {
|
||||||
|
setTables(importData.tables);
|
||||||
|
setRelationships(importData.relationships);
|
||||||
|
setAreas(importData.subjectAreas);
|
||||||
|
setNotes(importData.notes);
|
||||||
|
if (importData.title) {
|
||||||
|
setTitle(importData.title);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadDiagram = async (id) => {
|
||||||
|
await db.diagrams
|
||||||
|
.get(id)
|
||||||
|
.then((diagram) => {
|
||||||
|
if (diagram) {
|
||||||
|
setDiagramId(diagram.id);
|
||||||
|
setTitle(diagram.name);
|
||||||
|
setTables(diagram.tables);
|
||||||
|
setTypes(diagram.types);
|
||||||
|
setRelationships(diagram.references);
|
||||||
|
setAreas(diagram.areas);
|
||||||
|
setNotes(diagram.notes);
|
||||||
|
setTransform({
|
||||||
|
pan: diagram.pan,
|
||||||
|
zoom: diagram.zoom,
|
||||||
|
});
|
||||||
|
setUndoStack([]);
|
||||||
|
setRedoStack([]);
|
||||||
|
window.name = `d ${diagram.id}`;
|
||||||
|
} else {
|
||||||
|
Toast.error("Oops! Something went wrong.");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
Toast.error("Oops! Couldn't load diagram.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseSQLAndLoadDiagram = () => {
|
||||||
|
const parser = new Parser();
|
||||||
|
let ast = null;
|
||||||
|
try {
|
||||||
|
ast = parser.astify(importData.src, { database: "MySQL" });
|
||||||
|
} catch (err) {
|
||||||
|
Toast.error(
|
||||||
|
"Could not parse the sql file. Make sure there are no syntax errors."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const d = astToDiagram(ast);
|
||||||
|
if (importData.overwrite) {
|
||||||
|
setTables(d.tables);
|
||||||
|
setRelationships(d.relationships);
|
||||||
|
setNotes([]);
|
||||||
|
setAreas([]);
|
||||||
|
setTypes([]);
|
||||||
|
setUndoStack([]);
|
||||||
|
setRedoStack([]);
|
||||||
|
} else {
|
||||||
|
setTables((prev) => [...prev, ...d.tables]);
|
||||||
|
setRelationships((prev) => [...prev, ...d.relationships]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createNewDiagram = (id) => {
|
||||||
|
const newWindow = window.open("/editor");
|
||||||
|
newWindow.name = "lt " + id;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModalOnOk = async () => {
|
||||||
|
switch (modal) {
|
||||||
|
case MODAL.IMG:
|
||||||
|
saveAs(
|
||||||
|
exportData.data,
|
||||||
|
`${exportData.filename}.${exportData.extension}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
case MODAL.CODE: {
|
||||||
|
const blob = new Blob([exportData.data], {
|
||||||
|
type: "application/json",
|
||||||
|
});
|
||||||
|
saveAs(blob, `${exportData.filename}.${exportData.extension}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MODAL.IMPORT:
|
||||||
|
if (error.type !== STATUS.ERROR) {
|
||||||
|
setTransform((prev) => ({ ...prev, pan: { x: 0, y: 0 } }));
|
||||||
|
overwriteDiagram();
|
||||||
|
setImportData(null);
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
setUndoStack([]);
|
||||||
|
setRedoStack([]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case MODAL.IMPORT_SRC:
|
||||||
|
parseSQLAndLoadDiagram();
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
return;
|
||||||
|
case MODAL.OPEN:
|
||||||
|
if (selectedDiagramId === 0) return;
|
||||||
|
loadDiagram(selectedDiagramId);
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
return;
|
||||||
|
case MODAL.RENAME:
|
||||||
|
setPrevTitle(title);
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
return;
|
||||||
|
case MODAL.SAVEAS:
|
||||||
|
setTitle(saveAsTitle);
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
return;
|
||||||
|
case MODAL.NEW:
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
createNewDiagram(selectedTemplateId);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModalBody = () => {
|
||||||
|
switch (modal) {
|
||||||
|
case MODAL.IMPORT:
|
||||||
|
return (
|
||||||
|
<ImportDiagram
|
||||||
|
setImportData={setImportData}
|
||||||
|
error={error}
|
||||||
|
setError={setError}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case MODAL.IMPORT_SRC:
|
||||||
|
return (
|
||||||
|
<ImportSource
|
||||||
|
importData={importSource}
|
||||||
|
setImportData={setImportSource}
|
||||||
|
setError={setError}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case MODAL.NEW:
|
||||||
|
return (
|
||||||
|
<New
|
||||||
|
selectedTemplateId={selectedTemplateId}
|
||||||
|
setSelectedTemplateId={setSelectedTemplateId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case MODAL.RENAME:
|
||||||
|
return <Rename title={title} setTitle={setTitle} />;
|
||||||
|
case MODAL.OPEN:
|
||||||
|
return (
|
||||||
|
<Open
|
||||||
|
selectedDiagramId={selectedDiagramId}
|
||||||
|
setSelectedDiagramId={setSelectedDiagramId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case MODAL.SAVEAS:
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
placeholder="Diagram name"
|
||||||
|
value={saveAsTitle}
|
||||||
|
onChange={(v) => setSaveAsTitle(v)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case MODAL.CODE:
|
||||||
|
case MODAL.IMG:
|
||||||
|
if (exportData.data !== "" || exportData.data) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{modal === MODAL.IMG ? (
|
||||||
|
<Image src={exportData.data} alt="Diagram" height={280} />
|
||||||
|
) : (
|
||||||
|
<Editor
|
||||||
|
height="360px"
|
||||||
|
value={exportData.data}
|
||||||
|
language={exportData.extension}
|
||||||
|
options={{ readOnly: true }}
|
||||||
|
theme={settings.mode === "light" ? "light" : "vs-dark"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="text-sm font-semibold mt-2">Filename:</div>
|
||||||
|
<Input
|
||||||
|
value={exportData.filename}
|
||||||
|
placeholder="Filename"
|
||||||
|
suffix={<div className="p-2">{`.${exportData.extension}`}</div>}
|
||||||
|
onChange={(value) =>
|
||||||
|
setExportData((prev) => ({ ...prev, filename: value }))
|
||||||
|
}
|
||||||
|
field="filename"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="text-center my-3">
|
||||||
|
<Spin tip="Loading..." size="large" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SemiUIModal
|
||||||
|
title={getModalTitle(modal)}
|
||||||
|
visible={modal !== MODAL.NONE}
|
||||||
|
onOk={getModalOnOk}
|
||||||
|
afterClose={() => {
|
||||||
|
setExportData(() => ({
|
||||||
|
data: "",
|
||||||
|
extension: "",
|
||||||
|
filename: `${title}_${new Date().toISOString()}`,
|
||||||
|
}));
|
||||||
|
setError({
|
||||||
|
type: STATUS.NONE,
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
setImportData(null);
|
||||||
|
setImportSource({
|
||||||
|
src: "",
|
||||||
|
overwrite: true,
|
||||||
|
dbms: "MySQL",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
if (modal === MODAL.RENAME) setTitle(prevTitle);
|
||||||
|
setModal(MODAL.NONE);
|
||||||
|
}}
|
||||||
|
centered
|
||||||
|
closeOnEsc={true}
|
||||||
|
okText={getOkText(modal)}
|
||||||
|
okButtonProps={{
|
||||||
|
disabled:
|
||||||
|
(error && error?.type === STATUS.ERROR) ||
|
||||||
|
(modal === MODAL.IMPORT &&
|
||||||
|
(error.type === STATUS.ERROR || !importData)) ||
|
||||||
|
(modal === MODAL.RENAME && title === "") ||
|
||||||
|
((modal === MODAL.IMG || modal === MODAL.CODE) && !exportData.data) ||
|
||||||
|
(modal === MODAL.SAVEAS && saveAsTitle === "") ||
|
||||||
|
(modal === MODAL.IMPORT_SRC && importSource.src === ""),
|
||||||
|
}}
|
||||||
|
cancelText="Cancel"
|
||||||
|
width={modal === MODAL.NEW ? 740 : 600}
|
||||||
|
>
|
||||||
|
{getModalBody()}
|
||||||
|
</SemiUIModal>
|
||||||
|
);
|
||||||
|
}
|
43
src/components/EditorHeader/Modal/New.jsx
Normal file
43
src/components/EditorHeader/Modal/New.jsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { db } from "../../../data/db";
|
||||||
|
import { useSettings } from "../../../hooks";
|
||||||
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
import Thumbnail from "../../Thumbnail";
|
||||||
|
|
||||||
|
export default function New({ selectedTemplateId, setSelectedTemplateId }) {
|
||||||
|
const { settings } = useSettings();
|
||||||
|
const templates = useLiveQuery(() => db.templates.toArray());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-[360px] grid grid-cols-3 gap-2 overflow-auto px-1">
|
||||||
|
<div onClick={() => setSelectedTemplateId(0)}>
|
||||||
|
<div
|
||||||
|
className={`rounded-md h-[180px] border-2 hover:border-dashed ${
|
||||||
|
selectedTemplateId === 0 ? "border-blue-400" : "border-zinc-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Thumbnail i={0} diagram={{}} zoom={0.24} theme={settings.mode} />
|
||||||
|
</div>
|
||||||
|
<div className="text-center mt-1">Blank</div>
|
||||||
|
</div>
|
||||||
|
{templates?.map((temp, i) => (
|
||||||
|
<div key={i} onClick={() => setSelectedTemplateId(temp.id)}>
|
||||||
|
<div
|
||||||
|
className={`rounded-md h-[180px] border-2 hover:border-dashed ${
|
||||||
|
selectedTemplateId === temp.id
|
||||||
|
? "border-blue-400"
|
||||||
|
: "border-zinc-400"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Thumbnail
|
||||||
|
i={temp.id}
|
||||||
|
diagram={temp}
|
||||||
|
zoom={0.24}
|
||||||
|
theme={settings.mode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-center mt-1">{temp.title}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
73
src/components/EditorHeader/Modal/Open.jsx
Normal file
73
src/components/EditorHeader/Modal/Open.jsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { db } from "../../../data/db";
|
||||||
|
import { Banner } from "@douyinfe/semi-ui";
|
||||||
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
|
||||||
|
export default function Open({ selectedDiagramId, setSelectedDiagramId }) {
|
||||||
|
const diagrams = useLiveQuery(() => db.diagrams.toArray());
|
||||||
|
|
||||||
|
const getDiagramSize = (d) => {
|
||||||
|
const size = JSON.stringify(d).length;
|
||||||
|
let sizeStr;
|
||||||
|
if (size >= 1024 && size < 1024 * 1024)
|
||||||
|
sizeStr = (size / 1024).toFixed(1) + "KB";
|
||||||
|
else if (size >= 1024 * 1024)
|
||||||
|
sizeStr = (size / (1024 * 1024)).toFixed(1) + "MB";
|
||||||
|
else sizeStr = size + "B";
|
||||||
|
|
||||||
|
return sizeStr;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{diagrams?.length === 0 ? (
|
||||||
|
<Banner
|
||||||
|
fullMode={false}
|
||||||
|
type="info"
|
||||||
|
bordered
|
||||||
|
icon={null}
|
||||||
|
closeIcon={null}
|
||||||
|
description={<div>You have no saved diagrams.</div>}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="max-h-[360px]">
|
||||||
|
<table className="w-full text-left border-separate border-spacing-x-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Last Modified</th>
|
||||||
|
<th>Size</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{diagrams?.map((d) => {
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
key={d.id}
|
||||||
|
className={`${
|
||||||
|
selectedDiagramId === d.id
|
||||||
|
? "bg-blue-300 bg-opacity-30"
|
||||||
|
: "hover-1"
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedDiagramId(d.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<td className="py-1">
|
||||||
|
<i className="bi bi-file-earmark-text text-[16px] me-1 opacity-60" />
|
||||||
|
{d.name}
|
||||||
|
</td>
|
||||||
|
<td className="py-1">
|
||||||
|
{d.lastModified.toLocaleDateString() +
|
||||||
|
" " +
|
||||||
|
d.lastModified.toLocaleTimeString()}
|
||||||
|
</td>
|
||||||
|
<td className="py-1">{getDiagramSize(d)}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
11
src/components/EditorHeader/Modal/Rename.jsx
Normal file
11
src/components/EditorHeader/Modal/Rename.jsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Input } from "@douyinfe/semi-ui";
|
||||||
|
|
||||||
|
export default function Rename({ title, setTitle }) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
placeholder="Diagram name"
|
||||||
|
value={title}
|
||||||
|
onChange={(v) => setTitle(v)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
61
src/components/EditorHeader/SideSheet/Sidesheet.jsx
Normal file
61
src/components/EditorHeader/SideSheet/Sidesheet.jsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { SideSheet as SemiUISideSheet } from "@douyinfe/semi-ui";
|
||||||
|
import { SIDESHEET } from "../../../data/constants";
|
||||||
|
import { useSettings } from "../../../hooks";
|
||||||
|
import timeLine from "../../../assets/process.png";
|
||||||
|
import timeLineDark from "../../../assets/process_dark.png";
|
||||||
|
import todo from "../../../assets/calendar.png";
|
||||||
|
import Timeline from "./Timeline";
|
||||||
|
import Todo from "./Todo";
|
||||||
|
|
||||||
|
export default function Sidesheet({ type, onClose }) {
|
||||||
|
const { settings } = useSettings();
|
||||||
|
|
||||||
|
function getTitle(type) {
|
||||||
|
switch (type) {
|
||||||
|
case SIDESHEET.TIMELINE:
|
||||||
|
return (
|
||||||
|
<div className="flex items-center">
|
||||||
|
<img
|
||||||
|
src={settings.mode === "light" ? timeLine : timeLineDark}
|
||||||
|
className="w-7"
|
||||||
|
alt="chat icon"
|
||||||
|
/>
|
||||||
|
<div className="ms-3 text-lg">Timeline</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
case SIDESHEET.TODO:
|
||||||
|
return (
|
||||||
|
<div className="flex items-center">
|
||||||
|
<img src={todo} className="w-7" alt="todo icon" />
|
||||||
|
<div className="ms-3 text-lg">To-do list</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContent(type) {
|
||||||
|
switch (type) {
|
||||||
|
case SIDESHEET.TIMELINE:
|
||||||
|
return <Timeline />;
|
||||||
|
case SIDESHEET.TODO:
|
||||||
|
return <Todo />;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SemiUISideSheet
|
||||||
|
visible={type !== SIDESHEET.NONE}
|
||||||
|
onCancel={onClose}
|
||||||
|
width={340}
|
||||||
|
title={getTitle(type)}
|
||||||
|
style={{ paddingBottom: "16px" }}
|
||||||
|
bodyStyle={{ padding: "0px" }}
|
||||||
|
>
|
||||||
|
{getContent(type)}
|
||||||
|
</SemiUISideSheet>
|
||||||
|
);
|
||||||
|
}
|
32
src/components/EditorHeader/SideSheet/Timeline.jsx
Normal file
32
src/components/EditorHeader/SideSheet/Timeline.jsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { useUndoRedo } from "../../../hooks";
|
||||||
|
import { List } from "@douyinfe/semi-ui";
|
||||||
|
|
||||||
|
export default function Timeline() {
|
||||||
|
const { undoStack } = useUndoRedo();
|
||||||
|
|
||||||
|
if (undoStack.length > 0) {
|
||||||
|
return (
|
||||||
|
<List className="sidesheet-theme">
|
||||||
|
{[...undoStack].reverse().map((e, i) => (
|
||||||
|
<List.Item
|
||||||
|
key={i}
|
||||||
|
style={{ padding: "4px 18px 4px 18px" }}
|
||||||
|
className="hover-1"
|
||||||
|
>
|
||||||
|
<div className="flex items-center py-1 w-full">
|
||||||
|
<i className="block fa-regular fa-circle fa-xs" />
|
||||||
|
<div className="ms-2">{e.message}</div>
|
||||||
|
</div>
|
||||||
|
</List.Item>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="m-5 sidesheet-theme">
|
||||||
|
No activity was recorded. You have not added anything to your diagram
|
||||||
|
yet.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -19,8 +19,8 @@ import {
|
|||||||
IconDeleteStroked,
|
IconDeleteStroked,
|
||||||
IconCaretdown,
|
IconCaretdown,
|
||||||
} from "@douyinfe/semi-icons";
|
} from "@douyinfe/semi-icons";
|
||||||
import { State } from "../../data/constants";
|
import { State } from "../../../data/constants";
|
||||||
import { useTasks, useSaveState } from "../../hooks";
|
import { useTasks, useSaveState } from "../../../hooks";
|
||||||
|
|
||||||
const Priority = {
|
const Priority = {
|
||||||
NONE: 0,
|
NONE: 0,
|
@ -99,3 +99,28 @@ export const State = {
|
|||||||
LOADING: 3,
|
LOADING: 3,
|
||||||
ERROR: 4,
|
ERROR: 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MODAL = {
|
||||||
|
NONE: 0,
|
||||||
|
IMG: 1,
|
||||||
|
CODE: 2,
|
||||||
|
IMPORT: 3,
|
||||||
|
RENAME: 4,
|
||||||
|
OPEN: 5,
|
||||||
|
SAVEAS: 6,
|
||||||
|
NEW: 7,
|
||||||
|
IMPORT_SRC: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const STATUS = {
|
||||||
|
NONE: 0,
|
||||||
|
WARNING: 1,
|
||||||
|
ERROR: 2,
|
||||||
|
OK: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SIDESHEET = {
|
||||||
|
NONE: 0,
|
||||||
|
TODO: 1,
|
||||||
|
TIMELINE: 2,
|
||||||
|
};
|
252
src/utils/astToDiagram.js
Normal file
252
src/utils/astToDiagram.js
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
import { Cardinality } from "../data/constants";
|
||||||
|
|
||||||
|
export function astToDiagram(ast) {
|
||||||
|
const tables = [];
|
||||||
|
const relationships = [];
|
||||||
|
const inlineForeignKeys = [];
|
||||||
|
|
||||||
|
ast.forEach((e) => {
|
||||||
|
if (e.type === "create") {
|
||||||
|
if (e.keyword === "table") {
|
||||||
|
const table = {};
|
||||||
|
table.name = e.table[0].table;
|
||||||
|
table.comment = "";
|
||||||
|
table.color = "#175e7a";
|
||||||
|
table.fields = [];
|
||||||
|
table.indices = [];
|
||||||
|
table.x = 0;
|
||||||
|
table.y = 0;
|
||||||
|
e.create_definitions.forEach((d) => {
|
||||||
|
if (d.resource === "column") {
|
||||||
|
const field = {};
|
||||||
|
field.name = d.column.column;
|
||||||
|
field.type = d.definition.dataType;
|
||||||
|
field.comment = "";
|
||||||
|
field.unique = false;
|
||||||
|
if (d.unique) field.unique = true;
|
||||||
|
field.increment = false;
|
||||||
|
if (d.auto_increment) field.increment = true;
|
||||||
|
field.notNull = false;
|
||||||
|
if (d.nullable) field.notNull = true;
|
||||||
|
field.primary = false;
|
||||||
|
if (d.primary_key) field.primary = true;
|
||||||
|
field.default = "";
|
||||||
|
if (d.default_val) field.default = d.default_val.value.value;
|
||||||
|
if (d.definition["length"]) field.size = d.definition["length"];
|
||||||
|
field.check = "";
|
||||||
|
if (d.check) {
|
||||||
|
let check = "";
|
||||||
|
if (d.check.definition[0].left.column) {
|
||||||
|
let value = d.check.definition[0].right.value;
|
||||||
|
if (
|
||||||
|
d.check.definition[0].right.type === "double_quote_string" ||
|
||||||
|
d.check.definition[0].right.type === "single_quote_string"
|
||||||
|
)
|
||||||
|
value = "'" + value + "'";
|
||||||
|
check =
|
||||||
|
d.check.definition[0].left.column +
|
||||||
|
" " +
|
||||||
|
d.check.definition[0].operator +
|
||||||
|
" " +
|
||||||
|
value;
|
||||||
|
} else {
|
||||||
|
let value = d.check.definition[0].right.value;
|
||||||
|
if (
|
||||||
|
d.check.definition[0].left.type === "double_quote_string" ||
|
||||||
|
d.check.definition[0].left.type === "single_quote_string"
|
||||||
|
)
|
||||||
|
value = "'" + value + "'";
|
||||||
|
check =
|
||||||
|
value +
|
||||||
|
" " +
|
||||||
|
d.check.definition[0].operator +
|
||||||
|
" " +
|
||||||
|
d.check.definition[0].right.column;
|
||||||
|
}
|
||||||
|
field.check = check;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.fields.push(field);
|
||||||
|
} else if (d.resource === "constraint") {
|
||||||
|
if (d.constraint_type === "primary key") {
|
||||||
|
d.definition.forEach((c) => {
|
||||||
|
table.fields.forEach((f) => {
|
||||||
|
if (f.name === c.column && !f.primary) {
|
||||||
|
f.primary = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (d.constraint_type === "FOREIGN KEY") {
|
||||||
|
inlineForeignKeys.push({ ...d, startTable: e.table[0].table });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tables.push(table);
|
||||||
|
tables.forEach((e, i) => {
|
||||||
|
e.id = i;
|
||||||
|
e.fields.forEach((f, j) => {
|
||||||
|
f.id = j;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (e.keyword === "index") {
|
||||||
|
const index = {};
|
||||||
|
index.name = e.index;
|
||||||
|
index.unique = false;
|
||||||
|
if (e.index_type === "unique") index.unique = true;
|
||||||
|
index.fields = [];
|
||||||
|
e.index_columns.forEach((f) => index.fields.push(f.column));
|
||||||
|
|
||||||
|
let found = -1;
|
||||||
|
tables.forEach((t, i) => {
|
||||||
|
if (found !== -1) return;
|
||||||
|
if (t.name === e.table.table) {
|
||||||
|
t.indices.push(index);
|
||||||
|
found = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (found !== -1) tables[found].indices.forEach((i, j) => (i.id = j));
|
||||||
|
}
|
||||||
|
} else if (e.type === "alter") {
|
||||||
|
if (
|
||||||
|
e.expr[0].action === "add" &&
|
||||||
|
e.expr[0].create_definitions.constraint_type === "FOREIGN KEY"
|
||||||
|
) {
|
||||||
|
const relationship = {};
|
||||||
|
const startTable = e.table[0].table;
|
||||||
|
const startField = e.expr[0].create_definitions.definition[0].column;
|
||||||
|
const endTable =
|
||||||
|
e.expr[0].create_definitions.reference_definition.table[0].table;
|
||||||
|
const endField =
|
||||||
|
e.expr[0].create_definitions.reference_definition.definition[0]
|
||||||
|
.column;
|
||||||
|
let updateConstraint = "No action";
|
||||||
|
let deleteConstraint = "No action";
|
||||||
|
e.expr[0].create_definitions.reference_definition.on_action.forEach(
|
||||||
|
(c) => {
|
||||||
|
if (c.type === "on update") {
|
||||||
|
updateConstraint = c.value.value;
|
||||||
|
updateConstraint =
|
||||||
|
updateConstraint[0].toUpperCase() +
|
||||||
|
updateConstraint.substring(1);
|
||||||
|
} else if (c.type === "on delete") {
|
||||||
|
deleteConstraint = c.value.value;
|
||||||
|
deleteConstraint =
|
||||||
|
deleteConstraint[0].toUpperCase() +
|
||||||
|
deleteConstraint.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let startTableId = -1;
|
||||||
|
let startFieldId = -1;
|
||||||
|
let endTableId = -1;
|
||||||
|
let endFieldId = -1;
|
||||||
|
|
||||||
|
tables.forEach((t) => {
|
||||||
|
if (t.name === startTable) {
|
||||||
|
startTableId = t.id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.name === endTable) {
|
||||||
|
endTableId = t.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (startTableId === -1 || endTableId === -1) return;
|
||||||
|
|
||||||
|
tables[startTableId].fields.forEach((f) => {
|
||||||
|
if (f.name === startField) {
|
||||||
|
startFieldId = f.id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.name === endField) {
|
||||||
|
endFieldId = f.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (startFieldId === -1 || endFieldId === -1) return;
|
||||||
|
|
||||||
|
relationship.name = startTable + "_" + startField + "_fk";
|
||||||
|
relationship.startTableId = startTableId;
|
||||||
|
relationship.startFieldId = startFieldId;
|
||||||
|
relationship.endTableId = endTableId;
|
||||||
|
relationship.endFieldId = endFieldId;
|
||||||
|
relationship.updateConstraint = updateConstraint;
|
||||||
|
relationship.deleteConstraint = deleteConstraint;
|
||||||
|
relationship.cardinality = Cardinality.ONE_TO_ONE;
|
||||||
|
relationships.push(relationship);
|
||||||
|
|
||||||
|
relationships.forEach((r, i) => (r.id = i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inlineForeignKeys.forEach((fk) => {
|
||||||
|
const relationship = {};
|
||||||
|
const startTable = fk.startTable;
|
||||||
|
const startField = fk.definition[0].column;
|
||||||
|
const endTable = fk.reference_definition.table[0].table;
|
||||||
|
const endField = fk.reference_definition.definition[0].column;
|
||||||
|
let updateConstraint = "No action";
|
||||||
|
let deleteConstraint = "No action";
|
||||||
|
fk.reference_definition.on_action.forEach((c) => {
|
||||||
|
if (c.type === "on update") {
|
||||||
|
updateConstraint = c.value.value;
|
||||||
|
updateConstraint =
|
||||||
|
updateConstraint[0].toUpperCase() + updateConstraint.substring(1);
|
||||||
|
} else if (c.type === "on delete") {
|
||||||
|
deleteConstraint = c.value.value;
|
||||||
|
deleteConstraint =
|
||||||
|
deleteConstraint[0].toUpperCase() + deleteConstraint.substring(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let startTableId = -1;
|
||||||
|
let startFieldId = -1;
|
||||||
|
let endTableId = -1;
|
||||||
|
let endFieldId = -1;
|
||||||
|
|
||||||
|
tables.forEach((t) => {
|
||||||
|
if (t.name === startTable) {
|
||||||
|
startTableId = t.id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.name === endTable) {
|
||||||
|
endTableId = t.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (startTableId === -1 || endTableId === -1) return;
|
||||||
|
|
||||||
|
tables[startTableId].fields.forEach((f) => {
|
||||||
|
if (f.name === startField) {
|
||||||
|
startFieldId = f.id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.name === endField) {
|
||||||
|
endFieldId = f.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (startFieldId === -1 || endFieldId === -1) return;
|
||||||
|
|
||||||
|
relationship.name = startTable + "_" + startField + "_fk";
|
||||||
|
relationship.startTableId = startTableId;
|
||||||
|
relationship.startFieldId = startFieldId;
|
||||||
|
relationship.endTableId = endTableId;
|
||||||
|
relationship.endFieldId = endFieldId;
|
||||||
|
relationship.updateConstraint = updateConstraint;
|
||||||
|
relationship.deleteConstraint = deleteConstraint;
|
||||||
|
relationship.cardinality = Cardinality.ONE_TO_ONE;
|
||||||
|
relationships.push(relationship);
|
||||||
|
});
|
||||||
|
|
||||||
|
relationships.forEach((r, i) => (r.id = i));
|
||||||
|
|
||||||
|
return { tables, relationships };
|
||||||
|
}
|
44
src/utils/modalTitles.js
Normal file
44
src/utils/modalTitles.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { MODAL } from "../data/constants";
|
||||||
|
|
||||||
|
export const getModalTitle = (modal) => {
|
||||||
|
switch (modal) {
|
||||||
|
case MODAL.IMPORT:
|
||||||
|
case MODAL.IMPORT_SRC:
|
||||||
|
return "Import diagram";
|
||||||
|
case MODAL.CODE:
|
||||||
|
return "Export source";
|
||||||
|
case MODAL.IMG:
|
||||||
|
return "Export image";
|
||||||
|
case MODAL.RENAME:
|
||||||
|
return "Rename diagram";
|
||||||
|
case MODAL.OPEN:
|
||||||
|
return "Open diagram";
|
||||||
|
case MODAL.SAVEAS:
|
||||||
|
return "Save as";
|
||||||
|
case MODAL.NEW:
|
||||||
|
return "Create new diagram";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOkText = (modal) => {
|
||||||
|
switch (modal) {
|
||||||
|
case MODAL.IMPORT:
|
||||||
|
case MODAL.IMPORT_SRC:
|
||||||
|
return "Import";
|
||||||
|
case MODAL.CODE:
|
||||||
|
case MODAL.IMG:
|
||||||
|
return "Export";
|
||||||
|
case MODAL.RENAME:
|
||||||
|
return "Rename";
|
||||||
|
case MODAL.OPEN:
|
||||||
|
return "Open";
|
||||||
|
case MODAL.SAVEAS:
|
||||||
|
return "Save as";
|
||||||
|
case MODAL.NEW:
|
||||||
|
return "Create";
|
||||||
|
default:
|
||||||
|
return "Confirm";
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user