Skip to content

Commit

Permalink
Refactor component structure of modal and add export excel feature
Browse files Browse the repository at this point in the history
- Refactor the modal structure
- Allow renaming of files when exporting to PDF and DrawDB.
- Add a feature to exclude exporting relationships when exporting to SQL.
- Add an export to Excel feature
  • Loading branch information
cmc-pvhieu authored and phamhieu275 committed May 22, 2024
1 parent bf74463 commit 3c45476
Show file tree
Hide file tree
Showing 32 changed files with 2,186 additions and 865 deletions.
826 changes: 823 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"axios": "^1.6.2",
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.7",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"framer-motion": "^10.18.0",
"html-to-image": "^1.11.11",
Expand Down
214 changes: 22 additions & 192 deletions src/components/EditorHeader/ControlPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@ import {
Toast,
Popconfirm,
} from "@douyinfe/semi-ui";
import { toPng, toJpeg, toSvg } from "html-to-image";
import { saveAs } from "file-saver";
import {
jsonToMySQL,
jsonToPostgreSQL,
jsonToSQLite,
jsonToMariaDB,
jsonToSQLServer,
} from "../../utils/toSQL";
import { toPng } from "html-to-image";
import {
ObjectType,
Action,
Expand All @@ -38,7 +30,6 @@ import {
MODAL,
SIDESHEET,
} from "../../data/constants";
import jsPDF from "jspdf";
import { useHotkeys } from "react-hotkeys-hook";
import { Validator } from "jsonschema";
import { areaSchema, noteSchema, tableSchema } from "../../data/schemas";
Expand All @@ -60,8 +51,8 @@ import useSaveState from "../../hooks/useSaveState";
import { IconAddArea, IconAddNote, IconAddTable } from "../../icons";
import LayoutDropdown from "./LayoutDropdown";
import Sidesheet from "./SideSheet/Sidesheet";
import Modal from "./Modal/Modal";
import { useTranslation } from "react-i18next";
import ModalManager from "./ModalManager";

export default function ControlPanel({
diagramId,
Expand All @@ -72,13 +63,7 @@ export default function ControlPanel({
}) {
const [modal, setModal] = useState(MODAL.NONE);
const [sidesheet, setSidesheet] = useState(SIDESHEET.NONE);
const [prevTitle, setPrevTitle] = useState(title);
const [showEditName, setShowEditName] = useState(false);
const [exportData, setExportData] = useState({
data: null,
filename: `${title}_${new Date().toISOString()}`,
extension: "",
});
const { saveState, setSaveState } = useSaveState();
const { layout, setLayout } = useLayout();
const { settings, setSettings } = useSettings();
Expand Down Expand Up @@ -452,7 +437,7 @@ export default function ControlPanel({
}
};

const fileImport = () => setModal(MODAL.IMPORT);
const importDiagram = () => setModal(MODAL.IMPORT_DIAGRAM);
const viewGrid = () =>
setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid }));
const zoomIn = () =>
Expand Down Expand Up @@ -704,7 +689,6 @@ export default function ControlPanel({
rename: {
function: () => {
setModal(MODAL.RENAME);
setPrevTitle(title);
},
},
delete_diagram: {
Expand All @@ -730,7 +714,7 @@ export default function ControlPanel({
},
},
import_diagram: {
function: fileImport,
function: importDiagram,
shortcut: "Ctrl+I",
},
import_from_source: {
Expand All @@ -739,188 +723,33 @@ export default function ControlPanel({
export_as: {
children: [
{
PNG: () => {
toPng(document.getElementById("canvas")).then(function (dataUrl) {
setExportData((prev) => ({
...prev,
data: dataUrl,
extension: "png",
}));
});
setModal(MODAL.IMG);
},
},
{
JPEG: () => {
toJpeg(document.getElementById("canvas"), { quality: 0.95 }).then(
function (dataUrl) {
setExportData((prev) => ({
...prev,
data: dataUrl,
extension: "jpeg",
}));
},
);
setModal(MODAL.IMG);
},
},
{
JSON: () => {
setModal(MODAL.CODE);
const result = JSON.stringify(
{
tables: tables,
relationships: relationships,
notes: notes,
subjectAreas: areas,
types: types,
title: title,
},
null,
2,
);
setExportData((prev) => ({
...prev,
data: result,
extension: "json",
}));
},
},
{
SVG: () => {
const filter = (node) => node.tagName !== "i";
toSvg(document.getElementById("canvas"), { filter: filter }).then(
function (dataUrl) {
setExportData((prev) => ({
...prev,
data: dataUrl,
extension: "svg",
}));
},
);
setModal(MODAL.IMG);
IMAGE: () => {
setModal(MODAL.EXPORT_IMG);
},
},
{
PDF: () => {
const canvas = document.getElementById("canvas");
toJpeg(canvas).then(function (dataUrl) {
const doc = new jsPDF("l", "px", [
canvas.offsetWidth,
canvas.offsetHeight,
]);
doc.addImage(
dataUrl,
"jpeg",
0,
0,
canvas.offsetWidth,
canvas.offsetHeight,
);
doc.save(`${exportData.filename}.pdf`);
});
setModal(MODAL.EXPORT_PDF);
},
},
{
DRAWDB: () => {
const result = JSON.stringify(
{
author: "Unnamed",
title: title,
date: new Date().toISOString(),
tables: tables,
relationships: relationships,
notes: notes,
subjectAreas: areas,
types: types,
},
null,
2,
);
const blob = new Blob([result], {
type: "text/plain;charset=utf-8",
});
saveAs(blob, `${exportData.filename}.ddb`);
SQL: () => {
setModal(MODAL.EXPORT_SQL);
},
},
],
function: () => {},
},
export_source: {
children: [
{
MySQL: () => {
setModal(MODAL.CODE);
const src = jsonToMySQL({
tables: tables,
references: relationships,
types: types,
});
setExportData((prev) => ({
...prev,
data: src,
extension: "sql",
}));
EXCEL: async () => {
setModal(MODAL.EXPORT_EXCEL);
},
},
{
PostgreSQL: () => {
setModal(MODAL.CODE);
const src = jsonToPostgreSQL({
tables: tables,
references: relationships,
types: types,
});
setExportData((prev) => ({
...prev,
data: src,
extension: "sql",
}));
},
},
{
SQLite: () => {
setModal(MODAL.CODE);
const src = jsonToSQLite({
tables: tables,
references: relationships,
types: types,
});
setExportData((prev) => ({
...prev,
data: src,
extension: "sql",
}));
},
},
{
MariaDB: () => {
setModal(MODAL.CODE);
const src = jsonToMariaDB({
tables: tables,
references: relationships,
types: types,
});
setExportData((prev) => ({
...prev,
data: src,
extension: "sql",
}));
JSON: () => {
setModal(MODAL.EXPORT_JSON);
},
},
{
MSSQL: () => {
setModal(MODAL.CODE);
const src = jsonToSQLServer({
tables: tables,
references: relationships,
types: types,
});
setExportData((prev) => ({
...prev,
data: src,
extension: "sql",
}));
DRAWDB: () => {
setModal(MODAL.EXPORT_DIAGRAM);
},
},
],
Expand Down Expand Up @@ -1166,7 +995,7 @@ export default function ControlPanel({
},
};

useHotkeys("ctrl+i, meta+i", fileImport, { preventDefault: true });
useHotkeys("ctrl+i, meta+i", importDiagram, { preventDefault: true });
useHotkeys("ctrl+z, meta+z", undo, { preventDefault: true });
useHotkeys("ctrl+y, meta+y", redo, { preventDefault: true });
useHotkeys("ctrl+s, meta+s", save, { preventDefault: true });
Expand Down Expand Up @@ -1196,20 +1025,21 @@ export default function ControlPanel({
});
useHotkeys("ctrl+alt+w, meta+alt+w", fitWindow, { preventDefault: true });

const hideModal = () => {
setModal(MODAL.NONE);
};

return (
<>
{layout.header && header()}
{layout.toolbar && toolbar()}
<Modal
<ModalManager
modal={modal}
exportData={exportData}
setExportData={setExportData}
hideModal={hideModal}
title={title}
setTitle={setTitle}
setPrevTitle={setPrevTitle}
setDiagramId={setDiagramId}
setModal={setModal}
prevTitle={prevTitle}
/>
<Sidesheet
type={sidesheet}
Expand Down
26 changes: 26 additions & 0 deletions src/components/EditorHeader/Modal/BaseModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Modal as SemiUIModal } from "@douyinfe/semi-ui";
import { useTranslation } from "react-i18next";

export default function Modal({children, modalTitle, okText, onOk, onCancel, okBtnDisabled, width}) {
const { t } = useTranslation();

return (
<SemiUIModal
title={modalTitle || ""}
visible={true}
onOk={onOk}
onCancel={onCancel}
centered
closeOnEsc={true}
okText={okText || t("confirm")}
okButtonProps={{
disabled: okBtnDisabled
}}
cancelText={t("cancel")}
width={width || 600}
// bodyStyle={{ maxHeight: window.innerHeight - 280, overflow: "auto" }}
>
{children}
</SemiUIModal>
);
};
49 changes: 49 additions & 0 deletions src/components/EditorHeader/Modal/ExportDrawDB.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import {
useAreas,
useNotes,
useTables,
useTypes,
} from "../../../hooks";
import ExportModal from "./ExportModal";

export default function ExportDrawDB({ title, hideModal }) {
const { t } = useTranslation();
const { tables, relationships } = useTables();
const { notes } = useNotes();
const { areas } = useAreas();
const { types } = useTypes();

const rawData = JSON.stringify(
{
author: "Unnamed",
title: title,
date: new Date().toISOString(),
tables: tables,
relationships: relationships,
notes: notes,
subjectAreas: areas,
types: types,
},
null,
2,
);
const [exportData, setExportData] = useState({
data: new Blob(
[rawData],
{ type: "text/plain;charset=utf-8" }
),
filename: `${title}_${new Date().toISOString()}`,
extension: "ddb",
});

return (
<ExportModal
modalTitle={t("export_diagram")}
onCancel={hideModal}
exportData={exportData}
setExportData={setExportData}
/>
)
}
Loading

0 comments on commit 3c45476

Please sign in to comment.