Fix gists being controlled on button load

This commit is contained in:
1ilit 2024-08-31 19:49:43 +04:00
parent 65a86ee4f5
commit ed7fd87f7a
4 changed files with 116 additions and 68 deletions

View File

@ -1,4 +1,4 @@
import { useState } from "react"; import { useContext, useState } from "react";
import { import {
IconCaretdown, IconCaretdown,
IconChevronRight, IconChevronRight,
@ -71,7 +71,7 @@ import { exportSQL } from "../../utils/exportSQL";
import { databases } from "../../data/databases"; import { databases } from "../../data/databases";
import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { jsonToMermaid } from "../../utils/exportAs/mermaid";
import { isRtl } from "../../i18n/utils/rtl"; import { isRtl } from "../../i18n/utils/rtl";
import Share from "./Modal/Share"; import { IdContext } from "../Workspace";
export default function ControlPanel({ export default function ControlPanel({
diagramId, diagramId,
@ -114,6 +114,7 @@ export default function ControlPanel({
const { selectedElement, setSelectedElement } = useSelect(); const { selectedElement, setSelectedElement } = useSelect();
const { transform, setTransform } = useTransform(); const { transform, setTransform } = useTransform();
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const { setGistId } = useContext(IdContext);
const navigate = useNavigate(); const navigate = useNavigate();
const invertLayout = (component) => const invertLayout = (component) =>
@ -783,6 +784,7 @@ export default function ControlPanel({
setEnums([]); setEnums([]);
setUndoStack([]); setUndoStack([]);
setRedoStack([]); setRedoStack([]);
setGistId("");
}) })
.catch(() => Toast.error(t("oops_smth_went_wrong"))); .catch(() => Toast.error(t("oops_smth_went_wrong")));
}, },
@ -1372,12 +1374,11 @@ export default function ControlPanel({
onClick={() => setModal(MODAL.SHARE)} onClick={() => setModal(MODAL.SHARE)}
> >
{t("share")} {t("share")}
</Button>{" "} </Button>
</div> </div>
)} )}
{layout.toolbar && toolbar()} {layout.toolbar && toolbar()}
</div> </div>
<Share modal={modal} setModal={setModal}/>
<Modal <Modal
modal={modal} modal={modal}
exportData={exportData} exportData={exportData}

View File

@ -33,6 +33,7 @@ import ImportDiagram from "./ImportDiagram";
import ImportSource from "./ImportSource"; import ImportSource from "./ImportSource";
import SetTableWidth from "./SetTableWidth"; import SetTableWidth from "./SetTableWidth";
import Language from "./Language"; import Language from "./Language";
import Share from "./Share";
import CodeMirror from "@uiw/react-codemirror"; import CodeMirror from "@uiw/react-codemirror";
import { sql } from "@codemirror/lang-sql"; import { sql } from "@codemirror/lang-sql";
import { vscodeDark } from "@uiw/codemirror-theme-vscode"; import { vscodeDark } from "@uiw/codemirror-theme-vscode";
@ -256,7 +257,6 @@ export default function Modal({
}; };
const getModalBody = () => { const getModalBody = () => {
if (modal === MODAL.SHARE) return;
switch (modal) { switch (modal) {
case MODAL.IMPORT: case MODAL.IMPORT:
return ( return (
@ -341,8 +341,8 @@ export default function Modal({
return <SetTableWidth />; return <SetTableWidth />;
case MODAL.LANGUAGE: case MODAL.LANGUAGE:
return <Language />; return <Language />;
// case MODAL.SHARE: case MODAL.SHARE:
// return <Share setModal={setModal} />; return <Share title={title} />;
case MODAL.GITHUB_TOKEN: case MODAL.GITHUB_TOKEN:
return <GithubToken token={token} setToken={setToken} />; return <GithubToken token={token} setToken={setToken} />;
default: default:
@ -354,7 +354,7 @@ export default function Modal({
<SemiUIModal <SemiUIModal
style={isRtl(i18n.language) ? { direction: "rtl" } : {}} style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
title={getModalTitle(modal)} title={getModalTitle(modal)}
visible={modal !== MODAL.NONE && modal !== MODAL.SHARE} visible={modal !== MODAL.NONE}
onOk={getModalOnOk} onOk={getModalOnOk}
afterClose={() => { afterClose={() => {
setExportData(() => ({ setExportData(() => ({

View File

@ -1,16 +1,27 @@
import { Button, Input, Modal, Spin, Toast } from "@douyinfe/semi-ui"; import { Button, Input, Spin, Toast } from "@douyinfe/semi-ui";
import { MODAL } from "../../../data/constants";
import { useCallback, useContext, useEffect, useState, useMemo } from "react"; import { useCallback, useContext, useEffect, useState, useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Octokit } from "octokit"; import { Octokit } from "octokit";
import { IdContext } from "../../Workspace"; import { IdContext } from "../../Workspace";
import { IconLink } from "@douyinfe/semi-icons"; import { IconLink } from "@douyinfe/semi-icons";
import { isRtl } from "../../../i18n/utils/rtl"; import {
useAreas,
useDiagram,
useEnums,
useNotes,
useTypes,
} from "../../../hooks";
import { databases } from "../../../data/databases";
export default function Share({ modal, setModal }) { export default function Share({ title }) {
const { t, i18n } = useTranslation(); const { t } = useTranslation();
const { gistId, setGistId } = useContext(IdContext); const { gistId, setGistId } = useContext(IdContext);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(true);
const { tables, relationships, database } = useDiagram();
const { notes } = useNotes();
const { areas } = useAreas();
const { types } = useTypes();
const { enums } = useEnums();
const userToken = localStorage.getItem("github_token"); const userToken = localStorage.getItem("github_token");
const octokit = useMemo(() => { const octokit = useMemo(() => {
@ -23,6 +34,19 @@ export default function Share({ modal, setModal }) {
[gistId], [gistId],
); );
const diagramToString = useCallback(() => {
return JSON.stringify({
tables: tables,
relationships: relationships,
notes: notes,
subjectAreas: areas,
database: database,
...(databases[database].hasTypes && { types: types }),
...(databases[database].hasEnums && { enums: enums }),
title: title,
});
}, [areas, notes, tables, relationships, database, title, enums, types]);
const updateGist = useCallback(async () => { const updateGist = useCallback(async () => {
setLoading(true); setLoading(true);
try { try {
@ -30,8 +54,8 @@ export default function Share({ modal, setModal }) {
gist_id: gistId, gist_id: gistId,
description: "drawDB diagram", description: "drawDB diagram",
files: { files: {
"test.json": { "share.json": {
content: '{"Hello":"SEAMAN"}', content: diagramToString(),
}, },
}, },
headers: { headers: {
@ -43,7 +67,7 @@ export default function Share({ modal, setModal }) {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [gistId, octokit]); }, [gistId, octokit, diagramToString]);
const generateLink = useCallback(async () => { const generateLink = useCallback(async () => {
setLoading(true); setLoading(true);
@ -52,8 +76,8 @@ export default function Share({ modal, setModal }) {
description: "drawDB diagram", description: "drawDB diagram",
public: false, public: false,
files: { files: {
"test.json": { "share.json": {
content: '{"Hello":"WORLD"}', content: diagramToString(),
}, },
}, },
headers: { headers: {
@ -66,7 +90,7 @@ export default function Share({ modal, setModal }) {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [octokit, setGistId]); }, [octokit, setGistId, diagramToString]);
useEffect(() => { useEffect(() => {
const updateOrGenerateLink = async () => { const updateOrGenerateLink = async () => {
@ -83,7 +107,7 @@ export default function Share({ modal, setModal }) {
} }
}; };
updateOrGenerateLink(); updateOrGenerateLink();
}, [gistId, generateLink, setModal, updateGist]); }, [gistId, generateLink, updateGist]);
const copyLink = () => { const copyLink = () => {
navigator.clipboard navigator.clipboard
@ -96,48 +120,32 @@ export default function Share({ modal, setModal }) {
}); });
}; };
if (loading)
return (
<div className="text-blue-500 text-center">
<Spin size="middle" />
<div>{t("loading")}</div>
</div>
);
return ( return (
<Modal <div>
visible={modal === MODAL.SHARE} <div className="flex gap-3">
style={isRtl(i18n.language) ? { direction: "rtl" } : {}} <Input value={url} size="large" />
title={t("share")} <Button
footer={<></>} size="large"
onCancel={() => setModal(MODAL.NONE)} theme="solid"
centered icon={<IconLink />}
closeOnEsc={true} onClick={copyLink}
cancelText={t("cancel")} >
width={600} {t("copy_link")}
bodyStyle={{ </Button>
maxHeight: window.innerHeight - 280, </div>
overflow: "auto", <hr className="opacity-20 mt-3 mb-1" />
direction: "ltr", <div className="text-xs">
}} * Sharing this link will not create a live real-time collaboration
> session
{loading ? ( </div>
<div className="text-blue-500 text-center"> </div>
<Spin size="middle" />
<div>{t("loading")}</div>
</div>
) : (
<div>
<div className="flex gap-3">
<Input value={url} size="large" />
<Button
size="large"
theme="solid"
icon={<IconLink />}
onClick={copyLink}
>
{t("copy_link")}
</Button>
</div>
<hr className="opacity-20 mt-3 mb-1" />
<div className="text-xs">
* Sharing this link will not create a live real-time collaboration
session
</div>
</div>
)}
</Modal>
); );
} }

View File

@ -1,4 +1,10 @@
import { useState, useEffect, useCallback, createContext } from "react"; import {
useState,
useEffect,
useCallback,
createContext,
useMemo,
} from "react";
import ControlPanel from "./EditorHeader/ControlPanel"; import ControlPanel from "./EditorHeader/ControlPanel";
import Canvas from "./EditorCanvas/Canvas"; import Canvas from "./EditorCanvas/Canvas";
import { CanvasContextProvider } from "../context/CanvasContext"; import { CanvasContextProvider } from "../context/CanvasContext";
@ -23,6 +29,8 @@ import { Modal } from "@douyinfe/semi-ui";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { databases } from "../data/databases"; import { databases } from "../data/databases";
import { isRtl } from "../i18n/utils/rtl"; import { isRtl } from "../i18n/utils/rtl";
import { useSearchParams } from "react-router-dom";
import { Octokit } from "octokit";
export const IdContext = createContext({ gistId: "" }); export const IdContext = createContext({ gistId: "" });
@ -54,7 +62,13 @@ export default function WorkSpace() {
} = useDiagram(); } = useDiagram();
const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo(); const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo();
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
let [searchParams] = useSearchParams();
const userToken = localStorage.getItem("github_token");
const octokit = useMemo(() => {
return new Octokit({
auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN,
});
}, [userToken]);
const handleResize = (e) => { const handleResize = (e) => {
if (!resize) return; if (!resize) return;
const w = isRtl(i18n.language) ? window.innerWidth - e.clientX : e.clientX; const w = isRtl(i18n.language) ? window.innerWidth - e.clientX : e.clientX;
@ -307,6 +321,24 @@ export default function WorkSpace() {
selectedDb, selectedDb,
]); ]);
const loadFromGist = useCallback(
async (shareId) => {
try {
const res = await octokit.request(`GET /gists/${shareId}`, {
gist_id: shareId,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
});
const diagramSrc = res.data.files["share.json"].content;
console.log(diagramSrc);
} catch (e) {
console.log(e);
}
},
[octokit],
);
useEffect(() => { useEffect(() => {
if ( if (
tables?.length === 0 && tables?.length === 0 &&
@ -336,7 +368,9 @@ export default function WorkSpace() {
]); ]);
useEffect(() => { useEffect(() => {
setSaveState(State.SAVING); if (gistId && gistId !== "") {
setSaveState(State.SAVING);
}
}, [gistId, setSaveState]); }, [gistId, setSaveState]);
useEffect(() => { useEffect(() => {
@ -348,8 +382,13 @@ export default function WorkSpace() {
useEffect(() => { useEffect(() => {
document.title = "Editor | drawDB"; document.title = "Editor | drawDB";
load(); const shareId = searchParams.get("shareId");
}, [load]); if (shareId) {
loadFromGist(shareId);
} else {
load();
}
}, [load, searchParams, loadFromGist]);
return ( return (
<div className="h-full flex flex-col overflow-hidden theme"> <div className="h-full flex flex-col overflow-hidden theme">