mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-09-01 10:25:13 +00:00
update versions
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -30,6 +30,7 @@
|
|||||||
"jspdf": "^3.0.1",
|
"jspdf": "^3.0.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lexical": "^0.12.5",
|
"lexical": "^0.12.5",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.7.1",
|
"luxon": "^3.7.1",
|
||||||
"nanoid": "^5.1.5",
|
"nanoid": "^5.1.5",
|
||||||
"node-sql-parser": "^5.3.11",
|
"node-sql-parser": "^5.3.11",
|
||||||
@@ -4150,7 +4151,8 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash-es": {
|
"node_modules/lodash-es": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
"jspdf": "^3.0.1",
|
"jspdf": "^3.0.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lexical": "^0.12.5",
|
"lexical": "^0.12.5",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.7.1",
|
"luxon": "^3.7.1",
|
||||||
"nanoid": "^5.1.5",
|
"nanoid": "^5.1.5",
|
||||||
"node-sql-parser": "^5.3.11",
|
"node-sql-parser": "^5.3.11",
|
||||||
|
@@ -18,10 +18,12 @@ export async function create(filename, content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function patch(gistId, filename, content) {
|
export async function patch(gistId, filename, content) {
|
||||||
await axios.patch(`${baseUrl}/gists/${gistId}`, {
|
const { deleted } = await axios.patch(`${baseUrl}/gists/${gistId}`, {
|
||||||
filename,
|
filename,
|
||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function del(gistId) {
|
export async function del(gistId) {
|
||||||
@@ -52,12 +54,15 @@ export async function getVersion(gistId, sha) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getCommitsWithFile(gistId, file, perPage = 20, page = 1) {
|
export async function getCommitsWithFile(gistId, file, perPage = 20, page = 1) {
|
||||||
const res = await axios.get(`${baseUrl}/gists/${gistId}/file-versions/${file}`, {
|
const res = await axios.get(
|
||||||
params: {
|
`${baseUrl}/gists/${gistId}/file-versions/${file}`,
|
||||||
per_page: perPage,
|
{
|
||||||
page,
|
params: {
|
||||||
|
per_page: perPage,
|
||||||
|
page,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
@@ -1659,10 +1659,10 @@ export default function ControlPanel({
|
|||||||
<IconSaveStroked size="extra-large" />
|
<IconSaveStroked size="extra-large" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip content={t("revisions")} position="bottom">
|
<Tooltip content={t("versions")} position="bottom">
|
||||||
<button
|
<button
|
||||||
className="py-1 px-2 hover-2 rounded-sm text-xl -mt-0.5"
|
className="py-1 px-2 hover-2 rounded-sm text-xl -mt-0.5"
|
||||||
onClick={() => setSidesheet(SIDESHEET.REVISIONS)}
|
onClick={() => setSidesheet(SIDESHEET.VERSIONS)}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-code-branch" />{" "}
|
<i className="fa-solid fa-code-branch" />{" "}
|
||||||
</button>
|
</button>
|
||||||
|
@@ -55,13 +55,16 @@ export default function Share({ title, setModal }) {
|
|||||||
|
|
||||||
const unshare = useCallback(async () => {
|
const unshare = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await patch(gistId, SHARE_FILENAME, undefined);
|
const deleted = await patch(gistId, SHARE_FILENAME, undefined);
|
||||||
|
if (deleted) {
|
||||||
|
setGistId("");
|
||||||
|
}
|
||||||
setModal(MODAL.NONE);
|
setModal(MODAL.NONE);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
setError(e);
|
setError(e);
|
||||||
}
|
}
|
||||||
}, [gistId, setModal]);
|
}, [gistId, setModal, setGistId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateOrGenerateLink = async () => {
|
const updateOrGenerateLink = async () => {
|
||||||
|
@@ -1,195 +0,0 @@
|
|||||||
import { useCallback, useContext, useEffect, useState } from "react";
|
|
||||||
import { IdContext } from "../../Workspace";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Button, IconButton, Spin, Steps, Tag, Toast } from "@douyinfe/semi-ui";
|
|
||||||
import {
|
|
||||||
IconPlus,
|
|
||||||
IconChevronRight,
|
|
||||||
IconChevronLeft,
|
|
||||||
} from "@douyinfe/semi-icons";
|
|
||||||
import {
|
|
||||||
create,
|
|
||||||
getCommitsWithFile,
|
|
||||||
getVersion,
|
|
||||||
patch,
|
|
||||||
VERSION_FILENAME,
|
|
||||||
} from "../../../api/gists";
|
|
||||||
import { DateTime } from "luxon";
|
|
||||||
import {
|
|
||||||
useAreas,
|
|
||||||
useDiagram,
|
|
||||||
useEnums,
|
|
||||||
useLayout,
|
|
||||||
useNotes,
|
|
||||||
useTransform,
|
|
||||||
useTypes,
|
|
||||||
} from "../../../hooks";
|
|
||||||
import { databases } from "../../../data/databases";
|
|
||||||
|
|
||||||
export default function Revisions({ open, title, setTitle }) {
|
|
||||||
const { gistId, setVersion } = useContext(IdContext);
|
|
||||||
const { areas, setAreas } = useAreas();
|
|
||||||
const { setLayout } = useLayout();
|
|
||||||
const { database, tables, relationships, setTables, setRelationships } =
|
|
||||||
useDiagram();
|
|
||||||
const { notes, setNotes } = useNotes();
|
|
||||||
const { types, setTypes } = useTypes();
|
|
||||||
const { enums, setEnums } = useEnums();
|
|
||||||
const { transform } = useTransform();
|
|
||||||
const { t, i18n } = useTranslation();
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [revisions, setRevisions] = useState([]);
|
|
||||||
|
|
||||||
const diagramToString = useCallback(() => {
|
|
||||||
return JSON.stringify({
|
|
||||||
title,
|
|
||||||
tables,
|
|
||||||
relationships: relationships,
|
|
||||||
notes: notes,
|
|
||||||
subjectAreas: areas,
|
|
||||||
database: database,
|
|
||||||
...(databases[database].hasTypes && { types: types }),
|
|
||||||
...(databases[database].hasEnums && { enums: enums }),
|
|
||||||
transform: transform,
|
|
||||||
});
|
|
||||||
}, [
|
|
||||||
areas,
|
|
||||||
notes,
|
|
||||||
tables,
|
|
||||||
relationships,
|
|
||||||
database,
|
|
||||||
title,
|
|
||||||
enums,
|
|
||||||
types,
|
|
||||||
transform,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const loadVersion = useCallback(
|
|
||||||
async (sha) => {
|
|
||||||
try {
|
|
||||||
const version = await getVersion(gistId, sha);
|
|
||||||
setVersion(sha);
|
|
||||||
setLayout((prev) => ({ ...prev, readOnly: true }));
|
|
||||||
|
|
||||||
const content = version.data.files[VERSION_FILENAME].content;
|
|
||||||
|
|
||||||
const parsedDiagram = JSON.parse(content);
|
|
||||||
|
|
||||||
setTables(parsedDiagram.tables);
|
|
||||||
setRelationships(parsedDiagram.relationships);
|
|
||||||
setAreas(parsedDiagram.subjectAreas);
|
|
||||||
setNotes(parsedDiagram.notes);
|
|
||||||
setTitle(parsedDiagram.title);
|
|
||||||
|
|
||||||
if (databases[database].hasTypes) {
|
|
||||||
setTypes(parsedDiagram.types);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (databases[database].hasEnums) {
|
|
||||||
setEnums(parsedDiagram.enums);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
Toast.error("failed_to_load_diagram");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[
|
|
||||||
gistId,
|
|
||||||
setTables,
|
|
||||||
setRelationships,
|
|
||||||
setAreas,
|
|
||||||
setVersion,
|
|
||||||
setLayout,
|
|
||||||
database,
|
|
||||||
setNotes,
|
|
||||||
setTypes,
|
|
||||||
setEnums,
|
|
||||||
setTitle,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
const getRevisions = useCallback(
|
|
||||||
async (gistId) => {
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
const { data } = await getCommitsWithFile(gistId, VERSION_FILENAME);
|
|
||||||
|
|
||||||
setRevisions(
|
|
||||||
data.filter((version) => version.change_status.total !== 0),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
Toast.error(t("oops_smth_went_wrong"));
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[t],
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordVersion = async () => {
|
|
||||||
try {
|
|
||||||
if (gistId) {
|
|
||||||
console.log(gistId)
|
|
||||||
await patch(gistId, VERSION_FILENAME, diagramToString());
|
|
||||||
} else {
|
|
||||||
await create(VERSION_FILENAME, diagramToString());
|
|
||||||
}
|
|
||||||
await getRevisions(gistId);
|
|
||||||
} catch (e) {
|
|
||||||
Toast.error("failed_to_record_version");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (gistId && open) {
|
|
||||||
getRevisions(gistId);
|
|
||||||
}
|
|
||||||
}, [gistId, getRevisions, open]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx-5 relative h-full">
|
|
||||||
<div className="sticky top-0 z-10 sidesheet-theme pb-2 flex gap-2">
|
|
||||||
<IconButton icon={<IconChevronLeft />} title="Previous" />
|
|
||||||
<Button icon={<IconPlus />} block onClick={recordVersion}>
|
|
||||||
{t("record_version")}
|
|
||||||
</Button>
|
|
||||||
<IconButton icon={<IconChevronRight />} title="Next" />
|
|
||||||
</div>
|
|
||||||
{isLoading ? (
|
|
||||||
<div className="text-blue-500 text-center mt-3">
|
|
||||||
<Spin size="middle" />
|
|
||||||
<div>{t("loading")}</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{!gistId && <div className="my-3">{t("no_saved_revisions")}</div>}
|
|
||||||
{gistId && (
|
|
||||||
<div className="my-3 overflow-y-auto">
|
|
||||||
<Steps direction="vertical" type="basic">
|
|
||||||
{revisions.map((r, i) => (
|
|
||||||
<Steps.Step
|
|
||||||
key={r.version}
|
|
||||||
onClick={() => loadVersion(r.version)}
|
|
||||||
title={
|
|
||||||
<div className="flex justify-between items-center w-full">
|
|
||||||
<span>{`${t("version")} ${revisions.length - i}`}</span>
|
|
||||||
<Tag>{r.version.substring(0, 7)}</Tag>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
description={`${t("commited_at")} ${DateTime.fromISO(
|
|
||||||
r.committed_at,
|
|
||||||
)
|
|
||||||
.setLocale(i18n.language)
|
|
||||||
.toLocaleString(DateTime.DATETIME_MED)}`}
|
|
||||||
icon={<i className="text-sm fa-solid fa-asterisk" />}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Steps>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@@ -2,7 +2,7 @@ import { SideSheet as SemiUISideSheet } from "@douyinfe/semi-ui";
|
|||||||
import { SIDESHEET } from "../../../data/constants";
|
import { SIDESHEET } from "../../../data/constants";
|
||||||
import Timeline from "./Timeline";
|
import Timeline from "./Timeline";
|
||||||
import Todo from "./Todo";
|
import Todo from "./Todo";
|
||||||
import Revisions from "./Revisions";
|
import Versions from "./Versions";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function Sidesheet({ type, title, setTitle, onClose }) {
|
export default function Sidesheet({ type, title, setTitle, onClose }) {
|
||||||
@@ -14,8 +14,8 @@ export default function Sidesheet({ type, title, setTitle, onClose }) {
|
|||||||
return t("timeline");
|
return t("timeline");
|
||||||
case SIDESHEET.TODO:
|
case SIDESHEET.TODO:
|
||||||
return t("to_do");
|
return t("to_do");
|
||||||
case SIDESHEET.REVISIONS:
|
case SIDESHEET.VERSIONS:
|
||||||
return t("revisions");
|
return t("versions");
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -27,9 +27,9 @@ export default function Sidesheet({ type, title, setTitle, onClose }) {
|
|||||||
return <Timeline />;
|
return <Timeline />;
|
||||||
case SIDESHEET.TODO:
|
case SIDESHEET.TODO:
|
||||||
return <Todo />;
|
return <Todo />;
|
||||||
case SIDESHEET.REVISIONS:
|
case SIDESHEET.VERSIONS:
|
||||||
return (
|
return (
|
||||||
<Revisions
|
<Versions
|
||||||
open={type !== SIDESHEET.NONE}
|
open={type !== SIDESHEET.NONE}
|
||||||
title={title}
|
title={title}
|
||||||
setTitle={setTitle}
|
setTitle={setTitle}
|
||||||
|
@@ -12,8 +12,10 @@ import {
|
|||||||
getCommitsWithFile,
|
getCommitsWithFile,
|
||||||
getVersion,
|
getVersion,
|
||||||
patch,
|
patch,
|
||||||
|
get,
|
||||||
VERSION_FILENAME,
|
VERSION_FILENAME,
|
||||||
} from "../../../api/gists";
|
} from "../../../api/gists";
|
||||||
|
import _ from "lodash";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import {
|
import {
|
||||||
useAreas,
|
useAreas,
|
||||||
@@ -27,7 +29,7 @@ import {
|
|||||||
import { databases } from "../../../data/databases";
|
import { databases } from "../../../data/databases";
|
||||||
|
|
||||||
export default function Versions({ open, title, setTitle }) {
|
export default function Versions({ open, title, setTitle }) {
|
||||||
const { gistId, setVersion } = useContext(IdContext);
|
const { gistId, setGistId, setVersion } = useContext(IdContext);
|
||||||
const { areas, setAreas } = useAreas();
|
const { areas, setAreas } = useAreas();
|
||||||
const { setLayout } = useLayout();
|
const { setLayout } = useLayout();
|
||||||
const { database, tables, relationships, setTables, setRelationships } =
|
const { database, tables, relationships, setTables, setRelationships } =
|
||||||
@@ -126,12 +128,38 @@ export default function Versions({ open, title, setTitle }) {
|
|||||||
[t],
|
[t],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasDiagramChanged = async () => {
|
||||||
|
const previousVersion = await get(gistId);
|
||||||
|
const previousDiagram = JSON.parse(
|
||||||
|
previousVersion.data.files[VERSION_FILENAME]?.content,
|
||||||
|
);
|
||||||
|
const currentDiagram = {
|
||||||
|
title,
|
||||||
|
tables,
|
||||||
|
relationships: relationships,
|
||||||
|
notes: notes,
|
||||||
|
subjectAreas: areas,
|
||||||
|
database: database,
|
||||||
|
...(databases[database].hasTypes && { types: types }),
|
||||||
|
...(databases[database].hasEnums && { enums: enums }),
|
||||||
|
transform: transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
return !_.isEqual(previousDiagram, currentDiagram);
|
||||||
|
};
|
||||||
|
|
||||||
const recordVersion = async () => {
|
const recordVersion = async () => {
|
||||||
try {
|
try {
|
||||||
|
const hasChanges = await hasDiagramChanged();
|
||||||
|
if (!hasChanges) {
|
||||||
|
Toast.info(t("no_changes_to_record"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (gistId) {
|
if (gistId) {
|
||||||
await patch(gistId, VERSION_FILENAME, diagramToString());
|
await patch(gistId, VERSION_FILENAME, diagramToString());
|
||||||
} else {
|
} else {
|
||||||
await create(VERSION_FILENAME, diagramToString());
|
const id = await create(VERSION_FILENAME, diagramToString());
|
||||||
|
setGistId(id);
|
||||||
}
|
}
|
||||||
await getRevisions(gistId);
|
await getRevisions(gistId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@@ -99,7 +99,7 @@ export const SIDESHEET = {
|
|||||||
NONE: 0,
|
NONE: 0,
|
||||||
TODO: 1,
|
TODO: 1,
|
||||||
TIMELINE: 2,
|
TIMELINE: 2,
|
||||||
REVISIONS: 3,
|
VERSIONS: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DB = {
|
export const DB = {
|
||||||
|
@@ -259,16 +259,17 @@ const en = {
|
|||||||
tab_view: "Tab view",
|
tab_view: "Tab view",
|
||||||
label: "Label",
|
label: "Label",
|
||||||
many_side_label: "Many(n) side label",
|
many_side_label: "Many(n) side label",
|
||||||
revisions: "Revisions",
|
|
||||||
no_saved_revisions: "No saved revisions",
|
|
||||||
version: "Version",
|
version: "Version",
|
||||||
|
versions: "Versions",
|
||||||
|
no_saved_versions: "No saved versions",
|
||||||
record_version: "Record version",
|
record_version: "Record version",
|
||||||
commited_at: "Commited at",
|
commited_at: "Commited at",
|
||||||
read_only: "Read only",
|
read_only: "Read only",
|
||||||
continue: "Continue",
|
continue: "Continue",
|
||||||
restore_version: "Restore version",
|
restore_version: "Restore version",
|
||||||
restore_warning: "Loading another version will overwrite the current changes.",
|
restore_warning: "Loading another version will overwrite the current changes.",
|
||||||
return_to_current: "Return to diagram"
|
return_to_current: "Return to diagram",
|
||||||
|
no_changes_to_record: "No changes to record",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user